Projects
New Ticket     Wiki     Browse Source     Timeline     Roadmap     Bug Reports     Search

root/trunk/base/src/pextlib1.0/tracelib.c

Revision 41841, 12.3 KB (checked in by toby@…, 2 months ago)

make setrlimit stop complaining

  • Property svn:keywords set to Id
Line 
1/*
2 * tracelib.c
3 * $Id$
4 *
5 * Copyright (c) 2007 Eugene Pimenov (GSoC), The MacPorts Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of Darwinports Team nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <config.h>
34#include <string.h>
35#include <sys/time.h>
36#include <sys/resource.h>
37#include <unistd.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <sys/socket.h>
41#include <sys/types.h>
42#include <sys/select.h>
43#include <sys/un.h>
44#include <stdarg.h>
45#include <errno.h>
46#include <pthread.h>
47#include <limits.h>
48#include "tracelib.h"
49
50static char * name;
51static char * sandbox;
52static char * filemap, * filemap_end;
53static char * depends; 
54static int sock=-1;
55static int enable_fence=0;
56static Tcl_Interp * interp;
57static pthread_mutex_t sock_mutex=PTHREAD_MUTEX_INITIALIZER;
58static int cleanuping=0;
59static char * sdk=
60#ifdef TRACE_SDK
61        /*"MacOSX10.4u.sdk"*/
62        TRACE_SDK
63#else
64        0
65#endif
66;
67
68static void send_file_map(int sock);
69static void dep_check(int sock, const char * path);
70static void sandbox_violation(int sock, const char * path);
71static void ui_warn(const char * format, ...);
72static void ui_info(const char * format, ...);
73
74#define MAX_SOCKETS ((FD_SETSIZE)-1)
75
76static int TracelibSetNameCmd(Tcl_Interp * interp, int objc, Tcl_Obj *CONST objv[])
77{
78        if (objc != 3)
79        {
80                Tcl_WrongNumArgs(interp, 2, objv, "number of arguments should be exactly 3");
81                return TCL_ERROR;
82        }
83       
84        name=strdup(Tcl_GetString(objv[2]));
85       
86        return TCL_OK;
87}
88
89/*
90 * Save sandbox path into memory and prepare it for checks.
91 * For now it just change : to \0, and add last \0
92 * Input:
93 *  /dev/null:/dev/tty:/tmp
94 * In variable;
95 * /dev/null\0/dev/tty\0/tmp\0\0
96 */
97static int TracelibSetSandboxCmd(Tcl_Interp * interp, int objc, Tcl_Obj *CONST objv[])
98{
99        int len;
100        char * t;
101       
102        if (objc != 3)
103        {
104                Tcl_WrongNumArgs(interp, 2, objv, "number of arguments should be exactly 3");
105                return TCL_ERROR;
106        }
107       
108        len=strlen(Tcl_GetString(objv[2]))+2;
109        sandbox=(char*)malloc(len);
110        memset(sandbox, 0, len);
111        strcpy(sandbox, Tcl_GetString(objv[2]));
112        for(t=sandbox;(t=strchr(t+1, ':'));)
113        {
114                /* : -> \0 */
115                if(t[-1]!='\\')
116                        *t=0;
117                else
118                        /* \: -> : */
119                        /* TODO \\: -> \: */
120                        memmove(t-1, t, strlen(t));
121        }
122       
123        return TCL_OK;
124}
125
126/*
127 * Is there more data? (return 1 if more data in socket, 0 otherwise)
128 */
129static char can_I_recv_more(int sock)
130{
131        struct timeval tv;
132        fd_set fdr;
133        tv.tv_sec  = 0;
134        tv.tv_usec = 0;
135
136        FD_ZERO(&fdr);
137        FD_SET(sock, &fdr);
138        return select(sock+1, &fdr, 0, 0, &tv) == 1;
139}
140
141/*
142 * receive line from socket, parse it and send answer
143 */
144static char process_line(int sock)
145{
146        char * t, buf[1024]={0}, *f, *next_t;
147        int len;
148       
149        if((len=recv(sock, buf, sizeof(buf) - 1, 0))==-1)
150                return 0;
151        if(!len)
152                return 0;
153        buf[len]=0;
154        for(t=buf;*t&&t-buf<(int)sizeof(buf);t=next_t)
155        {
156                next_t = t+strlen(t)+1;
157                if(next_t == buf + sizeof(buf) && len == sizeof(buf) - 1)
158                {
159                        memmove(buf, t, next_t - t);
160                        t = buf;
161                        {
162                                char * end_of_t = t + strlen(t);
163                                *end_of_t = ' ';
164                                for(;can_I_recv_more(sock);)
165                                {
166                                        if(recv(sock, end_of_t, 1, 0) != 1)
167                                        {
168                                                ui_warn("recv failed");
169                                                return 0;
170                                        }
171                                        if(*end_of_t++ == 0)
172                                                break;
173                                }
174                        }
175                }
176   
177                f=strchr(t, '\t');
178                if(!f)
179                {
180                        ui_warn("malformed command %s", t);
181                        break;
182                }
183                *f++=0;
184
185                if(!strcmp(t, "filemap"))
186                {
187                        send_file_map(sock);
188                }else if(!strcmp(t, "sandbox_violation"))
189                {
190                        sandbox_violation(sock, f);
191                }else if(!strcmp(t, "dep_check"))
192                {
193                        dep_check(sock, f);
194                }else if(!strcmp(t, "execve"))
195                {
196                        /* ====================== */
197                        /* = TODO: do something = */
198                        /* ====================== */
199                }else
200                {
201                        ui_warn("unknown command %s (%s)", t, f);
202                }
203        }
204        return 1;
205}
206
207static void send_file_map(int sock)
208{
209        if(!filemap)
210        {
211                char * t, * _;
212               
213                filemap=(char*)malloc(1024);
214                t=filemap;
215               
216                #define append_allow(path, resolution) do{strcpy(t, path); t+=strlen(t)+1; *t++=resolution; *t++=0;}while(0);
217                if(enable_fence)
218                {
219                        for(_=sandbox; *_; _+=strlen(_)+1)
220                                append_allow(_, 0);
221                       
222                        append_allow("/bin", 0);
223                        append_allow("/sbin", 0);
224                        append_allow("/dev", 0);
225                        append_allow(Tcl_GetVar(interp, "macports::prefix", TCL_GLOBAL_ONLY), 2);
226                        append_allow("/Applications/MacPorts", 0);
227                        /* If there is no SDK we will allow everything in /usr /System/Library etc, else add binaries to allow, and redirect root to SDK. */
228                        if(sdk&&*sdk)
229                        {
230                                char buf[260]="/Developer/SDKs/";
231                                strcat(buf, sdk);
232                       
233                                append_allow("/usr/bin", 0);
234                                append_allow("/usr/sbin", 0);
235                                append_allow("/usr/libexec/gcc", 0);
236                                append_allow("/System/Library/Perl", 0);
237                                append_allow("/usr/X11R6/bin", 0);
238                                append_allow("/", 1);
239                                strcpy(t-1, buf);
240                                t+=strlen(t)+1;
241                        }else
242                        {
243                                append_allow("/usr", 0);
244                                append_allow("/System/Library", 0);
245                                append_allow("/Library", 0);
246                                append_allow("/Developer", 0);
247                        }
248                }else
249                        append_allow("/", 0);
250                filemap_end=t;
251                #undef append_allow
252        }
253       
254        {
255                size_t s=filemap_end-filemap;
256                send(sock, &s, sizeof(s), 0);
257                send(sock, filemap, s, 0);
258        }
259}
260
261static void sandbox_violation(int sock UNUSED, const char * path)
262{
263        Tcl_SetVar(interp, "path", path, 0);
264        Tcl_Eval(interp, "slave_add_sandbox_violation $path");
265        Tcl_UnsetVar(interp, "path", 0);
266}
267
268static void dep_check(int sock, const char * path)
269{
270        char * port=0;
271        size_t len=1;
272        char resolution; 
273       
274        /* If there aren't deps then allow anything. (Useful for extract) */
275        if(!depends)
276                resolution='+';
277        else
278        {
279                resolution='!';
280               
281                Tcl_SetVar(interp, "path", path, 0);
282                Tcl_Eval(interp, "registry::file_registered $path");
283                port=strdup(Tcl_GetStringResult(interp));
284                Tcl_UnsetVar(interp, "path", 0);
285       
286                if(*port!='0'||port[1])
287                {
288                        char * t;
289               
290                        t=depends;
291                        for(;*t;t+=strlen(t)+1)
292                        {
293                                if(!strcmp(t, port))
294                                {
295                                        resolution='+';
296                                        break;
297                                }
298                        }
299                }else if(*port=='0'&&!port[1])
300                        strcpy(port, "*unknown*");
301        }
302       
303        if(resolution!='+')
304                ui_info("trace: access denied to %s (%s)", path, port);
305
306        if(port)
307                free(port);
308       
309        if(send(sock, &len, sizeof(len), 0)==-1)
310                ui_warn("tracelib send failed");
311        if(send(sock, &resolution, 1, 0)==-1)
312                ui_warn("tracelib send failed");
313}
314
315static void ui_msg(const char * severity, const char * format, va_list va)
316{
317        char buf[1024], tclcmd[32];
318       
319        vsprintf(buf, format, va);
320       
321        sprintf(tclcmd, "ui_%s $warn", severity);
322       
323        Tcl_SetVar(interp, "warn", buf, 0);
324       
325        Tcl_Eval(interp, tclcmd);
326        Tcl_UnsetVar(interp, "warn", 0);
327       
328}
329
330static void ui_warn(const char * format, ...)
331{
332        va_list va;
333       
334        va_start(va, format);
335                ui_msg("warn", format, va);
336        va_end(va);
337}
338
339static void ui_info(const char * format, ...)
340{
341        va_list va;
342       
343        va_start(va, format);
344                ui_msg("msg", format, va);
345        va_end(va);
346}
347
348static int TracelibRunCmd(Tcl_Interp * in)
349{
350        struct sockaddr_un sun;
351        fd_set fdr;
352        int i;
353        int max_fd, max_used, socks[MAX_SOCKETS];
354        struct rlimit rl;
355       
356        pthread_mutex_lock(&sock_mutex);
357        if(cleanuping)
358        {
359                pthread_mutex_unlock(&sock_mutex);
360                return 0;
361        }
362        sock=socket(AF_UNIX, SOCK_STREAM, 0);
363        pthread_mutex_unlock(&sock_mutex);
364       
365        interp=in;
366       
367        rl.rlim_cur=rl.rlim_max=RLIM_INFINITY;
368#if defined(__APPLE__) && defined(OPEN_MAX)
369        if (OPEN_MAX < rl.rlim_cur)
370                rl.rlim_cur = OPEN_MAX;
371#endif
372        if(setrlimit(RLIMIT_NOFILE, &rl)==-1)
373        {
374                ui_warn("setrlimit failed (%d)", errno);
375        }
376
377       
378        sun.sun_family=AF_UNIX;
379        strcpy(sun.sun_path, name);
380        if(bind(sock, (struct sockaddr*)&sun, sizeof(sun))==-1)
381        {
382                Tcl_SetResult(interp, "Cannot bind socket", TCL_STATIC);
383                return TCL_ERROR;
384        }
385       
386        listen(sock, 5);
387        max_used=0;
388        max_fd=sock;
389       
390        for(;sock!=-1&&!cleanuping;)
391        {
392                FD_ZERO(&fdr);
393                FD_SET(sock, &fdr);
394                for(i=0;i<max_used;++i)
395                        FD_SET(socks[i], &fdr);
396                               
397                if(select(max_fd+1, &fdr, 0, 0, 0)<1)
398                {
399                        continue;
400                }
401                if(sock==-1)
402                {
403                        break;
404                }
405                if(FD_ISSET(sock, &fdr))
406                {
407                        int s;
408                        s=accept(sock, 0, 0);
409                       
410                        if(s==-1)
411                        {
412                                if(cleanuping)
413                                        break;
414                                else
415                                        ui_warn("tracelib: accept return -1 (errno: %d)", errno);
416                                /* failed sometimes and i dunno why*/
417                                continue;
418                        }
419                        /* Temporary solution, it's better to regenerate this variable in each iteration, because when closing socket we'll get it too high */                         
420                        if(s>max_fd)
421                                max_fd=s;
422                        for(i=0;i<max_used;++i)
423                                if(!socks[i])
424                                {
425                                        socks[i]=s;
426                                        break;
427                                }
428                        if(i==max_used)
429                        {
430                                if(max_used==MAX_SOCKETS-1)
431                                {
432                                        ui_warn("There is no place to store socket");
433                                        close(s);
434                                }
435                                else
436                                        socks[max_used++]=s;
437                        }
438                }
439               
440                for(i=0;i<max_used;++i)
441                {
442                        if(!socks[i])
443                                continue;
444                        if(FD_ISSET(socks[i], &fdr))
445                        {
446                                if(!process_line(socks[i]))
447                                {
448                                        close(socks[i]);
449                                        socks[i]=0;
450                                        continue;
451                                }
452                        }
453                }
454        }
455       
456        for(i=0;i<max_used;++i)
457        {
458                if(socks[i])
459                {
460                        close(socks[i]);
461                        socks[i]=0;
462                }
463        }
464       
465        return TCL_OK;
466}
467
468static int TracelibCleanCmd(Tcl_Interp * interp UNUSED)
469{
470        #define safe_free(x) do{free(x); x=0;}while(0);
471        cleanuping=1;
472        pthread_mutex_lock(&sock_mutex);
473        if(sock!=-1)
474        {
475                /* shutdown(sock, SHUT_RDWR);*/
476                close(sock);
477                sock=-1;
478        }
479        pthread_mutex_unlock(&sock_mutex);
480        if(name)
481        {
482                unlink(name);
483                safe_free(name);
484        }
485        if(filemap)
486                safe_free(filemap);
487        if(depends)
488                safe_free(depends);
489        enable_fence=0;
490        #undef safe_free
491        cleanuping=0;
492        return TCL_OK;
493}
494
495static int TracelibCloseSocketCmd(Tcl_Interp * interp UNUSED)
496{
497        cleanuping=1;
498        pthread_mutex_lock(&sock_mutex);
499        if(sock!=-1)
500        {
501                /*shutdown(sock, SHUT_RDWR);*/
502                close(sock);
503                sock=-1;
504        }
505        pthread_mutex_unlock(&sock_mutex);
506        return TCL_OK;
507}
508
509static int TracelibSetDeps(Tcl_Interp * interp UNUSED, int objc, Tcl_Obj* CONST objv[])
510{
511        char * t, * d;
512        size_t l;
513        if(objc!=3)
514        {
515                Tcl_WrongNumArgs(interp, 2, objv, "number of arguments should be exactly 3");
516                return TCL_ERROR;
517        }
518       
519        d=Tcl_GetString(objv[2]);
520        l=strlen(d);
521        depends=malloc(l+2);
522        depends[l+1]=0;
523        strcpy(depends, d);
524        for(t=depends;*t;++t)
525                if(*t==' ')
526                        *t++=0;
527       
528        return TCL_OK;
529}
530
531static int TracelibEnableFence(Tcl_Interp * interp UNUSED)
532{
533        enable_fence=1;
534        if(filemap)
535                free(filemap);
536        filemap=0;
537        return TCL_OK;
538}
539
540int TracelibCmd(ClientData clientData UNUSED, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[])
541{
542        int result=TCL_OK;
543        static const char * options[]={"setname", "run", "clean", "setsandbox", "closesocket", "setdeps", "enablefence", 0};
544        typedef enum 
545        {
546                kSetName,
547                kRun,
548                kClean,
549                kSetSandbox,
550                kCloseSocket,
551                kSetDeps,
552                kEnableFence
553        } EOptions;
554        EOptions current_option;
555       
556        /* There is no args for commands now. */
557        if (objc <2)
558        {
559                Tcl_WrongNumArgs(interp, 1, objv, "option");
560                return TCL_ERROR;
561        }
562       
563        result=Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, (int*)&current_option);
564        if(result==TCL_OK)
565        {
566                switch(current_option)
567                {
568                case kSetName:
569                        result=TracelibSetNameCmd(interp, objc, objv);
570                        break;
571                case kRun:
572                        result=TracelibRunCmd(interp);
573                        break;
574                case kClean:
575                        result=TracelibCleanCmd(interp);
576                        break;
577                case kCloseSocket:
578                        result=TracelibCloseSocketCmd(interp);
579                        break;
580                case kSetSandbox:
581                        result=TracelibSetSandboxCmd(interp, objc, objv);
582                        break;
583                case kSetDeps:
584                        result=TracelibSetDeps(interp, objc, objv);
585                        break;
586                case kEnableFence:
587                        result=TracelibEnableFence(interp);
588                        break;
589                }
590        }
591       
592        return result;
593}
Note: See TracBrowser for help on using the browser.