source: trunk/base/src/darwintracelib1.0/darwintrace.c @ 30381

Last change on this file since 30381 was 30381, checked in by epimenov@…, 12 years ago

tracelib: hackaround. Something strange happend, seems socket come broken after execve.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.6 KB
Line 
1/*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 * Copyright (c) 2005-2006 Paul Guyot <pguyot@kallisys.net>,
4 * All rights reserved.
5 *
6 * $Id: darwintrace.c 30381 2007-10-26 03:39:02Z epimenov@macports.org $
7 *
8 * @APPLE_BSD_LICENSE_HEADER_START@
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1.  Redistributions of source code must retain the above copyright
15 *     notice, this list of conditions and the following disclaimer.
16 * 2.  Redistributions in binary form must reproduce the above copyright
17 *     notice, this list of conditions and the following disclaimer in the
18 *     documentation and/or other materials provided with the distribution.
19 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
20 *     its contributors may be used to endorse or promote products derived
21 *     from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
27 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 * @APPLE_BSD_LICENSE_HEADER_END@
35 */
36
37#ifdef HAVE_CONFIG_H
38#include <config.h>
39#endif
40
41#ifdef HAVE_CRT_EXTERNS_H
42#include <crt_externs.h>
43#endif
44
45#ifdef HAVE_SYS_PATHS_H
46#include <sys/paths.h>
47#endif
48
49#include <fcntl.h>
50#include <stdarg.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include <unistd.h>
55#include <sys/types.h>
56#include <sys/stat.h>
57#include <sys/param.h>
58#include <sys/syscall.h>
59#include <errno.h>
60#include <sys/socket.h>
61#include <sys/un.h>
62
63#ifndef HAVE_STRLCPY
64/* Define strlcpy if it's not available. */
65size_t strlcpy(char* dst, const char* src, size_t size);
66size_t strlcpy(char* dst, const char* src, size_t size)
67{
68        size_t result = strlen(src);
69        if (size > 0)
70        {
71                size_t copylen = size - 1;
72                if (copylen > result)
73                {
74                        copylen = result;
75                }
76                memcpy(dst, src, copylen);
77                dst[copylen] = 0;
78        }
79        return result;
80}
81#endif
82
83/*
84 * Compile time options:
85 * DARWINTRACE_SHOW_PROCESS: show the process id of every access
86 * DARWINTRACE_LOG_CREATE: log creation of files as well.
87 * DARWINTRACE_SANDBOX: control creation, deletion and writing to files and dirs.
88 * DARWINTRACE_LOG_FULL_PATH: use F_GETPATH to log the full path.
89 * DARWINTRACE_DEBUG_OUTPUT: verbose output of stuff to debug darwintrace.
90 *
91 * global variables (only checked when setup is first called)
92 * DARWINTRACE_LOG
93 *    path to the log file (no logging happens if it's unset).
94 * DARWINTRACE_SANDBOX_BOUNDS
95 *    : separated allowed paths for the creation of files.
96 *    \: -> :
97 *    \\ -> \
98 */
99
100#ifndef DARWINTRACE_SHOW_PROCESS
101#define DARWINTRACE_SHOW_PROCESS 0
102#endif
103#ifndef DARWINTRACE_LOG_CREATE
104#define DARWINTRACE_LOG_CREATE 0
105#endif
106#ifndef DARWINTRACE_SANDBOX
107#define DARWINTRACE_SANDBOX 1
108#endif
109#ifndef DARWINTRACE_DEBUG_OUTPUT
110#define DARWINTRACE_DEBUG_OUTPUT 0
111#endif
112#ifndef DARWINTRACE_LOG_FULL_PATH
113#define DARWINTRACE_LOG_FULL_PATH 1
114#endif
115
116#ifndef DEFFILEMODE
117#define DEFFILEMODE 0666
118#endif
119
120/*
121 * Prototypes.
122 */
123inline int __darwintrace_strbeginswith(const char* str, const char* prefix);
124inline void __darwintrace_log_op(const char* op, const char* path, int fd);
125void __darwintrace_copy_env() __attribute__((constructor));
126inline char* __darwintrace_alloc_env(const char* varName, const char* varValue);
127inline char* const* __darwintrace_restore_env(char* const envp[]);
128inline void __darwintrace_setup();
129inline void __darwintrace_cleanup_path(char *path);
130static char * exchange_with_port(const char * buf, size_t len, int answer, char failures);
131
132#define START_FD 81
133static int __darwintrace_fd = -1;
134#define BUFFER_SIZE     1024
135
136/**
137 * filemap: path\0whattodo\0path\0whattodo\0\0
138 * path: begin of path (for example /opt)
139 * whattodo:
140 *   0     -- allow
141 *   1PATH -- map
142 *   2     -- ask for allow
143**/
144static char * filemap=0;
145
146/* copy of the global variables */
147static char* __env_dyld_insert_libraries;
148static char* __env_dyld_force_flat_namespace;
149static char* __env_darwintrace_log;
150
151#if __STDC_VERSION__>=199901L
152#if DARWINTRACE_DEBUG_OUTPUT
153#define dprintf(...) fprintf(stderr, __VA_ARGS__)
154#else
155#define dprintf(...)
156#endif
157#else
158#if DARWINTRACE_DEBUG_OUTPUT
159#define dprintf(format, param) fprintf(stderr, format, param)
160#else
161#define dprintf(format, param)
162#endif
163#endif
164
165/*
166 * char wait_for_socket(int sock, char w)
167 * Function used for read/write operation to socket...
168 * Args:
169 *  sock - socket
170 *  w - what should socket do in next operation. 1 for write, 0 for read
171 * Return value:
172 *  1 - everything is ok, we can read/write to/from it
173 *  0 - something's went wrong
174 */
175static int wait_for_socket(int sock, char w)
176{
177        struct timeval tv;
178        fd_set fds;
179       
180        if(sock==-1)
181                return 0;
182       
183        tv.tv_sec=10;
184        tv.tv_usec=0;
185        FD_ZERO(&fds);
186        FD_SET(sock, &fds);
187        if(select(sock+1, (w==0 ? &fds : 0), (w==1 ? &fds : 0), 0, &tv)<1)
188                return 0;
189        return FD_ISSET(sock, &fds)!=0;
190}
191
192
193/*
194 * return 0 if str doesn't begin with prefix, 1 otherwise.
195 */
196inline int __darwintrace_strbeginswith(const char* str, const char* prefix) {
197        char theCharS;
198        char theCharP;
199        do {
200                theCharS = *str++;
201                theCharP = *prefix++;
202        } while(theCharP && (theCharP == theCharS));
203        return (theCharP == 0);
204}
205
206/*
207 * Copy the environment variables, if they're defined.
208 */
209void __darwintrace_copy_env() {
210        char* theValue;
211        theValue = getenv("DYLD_INSERT_LIBRARIES");
212        if (theValue != NULL) {
213                __env_dyld_insert_libraries = strdup(theValue);
214        } else {
215                __env_dyld_insert_libraries = NULL;
216        }
217        theValue = getenv("DYLD_FORCE_FLAT_NAMESPACE");
218        if (theValue != NULL) {
219                __env_dyld_force_flat_namespace = strdup(theValue);
220        } else {
221                __env_dyld_force_flat_namespace = NULL;
222        }
223        theValue = getenv("DARWINTRACE_LOG");
224        if (theValue != NULL) {
225                __env_darwintrace_log = strdup(theValue);
226        } else {
227                __env_darwintrace_log = NULL;
228        }
229}
230
231/*
232 * Allocate a X=Y string where X is the variable name and Y its value.
233 * Return the new string.
234 *
235 * If the value is NULL, return NULL.
236 */
237inline char* __darwintrace_alloc_env(const char* varName, const char* varValue) {
238        char* theResult = NULL;
239        if (varValue) {
240                int theSize = strlen(varName) + strlen(varValue) + 2;
241                theResult = (char*) malloc(theSize);
242                sprintf(theResult, "%s=%s", varName, varValue);
243                theResult[theSize - 1] = 0;
244        }
245       
246        return theResult;
247}
248
249/*
250 * This function checks that envp contains the global variables we had when the
251 * library was loaded and modifies it if it doesn't.
252 */
253inline char* const* __darwintrace_restore_env(char* const envp[]) {
254        /* allocate the strings. */
255        /* we don't care about the leak here because we're going to call execve,
256     * which, if it succeeds, will get rid of our heap */
257        char* dyld_insert_libraries_ptr =       
258                __darwintrace_alloc_env(
259                        "DYLD_INSERT_LIBRARIES",
260                        __env_dyld_insert_libraries);
261        char* dyld_force_flat_namespace_ptr =   
262                __darwintrace_alloc_env(
263                        "DYLD_FORCE_FLAT_NAMESPACE",
264                        __env_dyld_force_flat_namespace);
265        char* darwintrace_log_ptr =     
266                __darwintrace_alloc_env(
267                        "DARWINTRACE_LOG",
268                        __env_darwintrace_log);
269
270        char* const * theEnvIter = envp;
271        int theEnvLength = 0;
272        char** theCopy;
273        char** theCopyIter;
274
275        while (*theEnvIter != NULL) {
276                theEnvLength++;
277                theEnvIter++;
278        }
279
280        /* 5 is sufficient for the four variables we copy and the terminator */
281        theCopy = (char**) malloc(sizeof(char*) * (theEnvLength + 5));
282        theEnvIter = envp;
283        theCopyIter = theCopy;
284
285        while (*theEnvIter != NULL) {
286                char* theValue = *theEnvIter;
287                if (__darwintrace_strbeginswith(theValue, "DYLD_INSERT_LIBRARIES=")) {
288                        theValue = dyld_insert_libraries_ptr;
289                        dyld_insert_libraries_ptr = NULL;
290                } else if (__darwintrace_strbeginswith(theValue, "DYLD_FORCE_FLAT_NAMESPACE=")) {
291                        theValue = dyld_force_flat_namespace_ptr;
292                        dyld_force_flat_namespace_ptr = NULL;
293                } else if (__darwintrace_strbeginswith(theValue, "DARWINTRACE_LOG=")) {
294                        theValue = darwintrace_log_ptr;
295                        darwintrace_log_ptr = NULL;
296                }
297               
298                if (theValue) {
299                        *theCopyIter++ = theValue;
300                }
301
302                theEnvIter++;
303        }
304       
305        if (dyld_insert_libraries_ptr) {
306                *theCopyIter++ = dyld_insert_libraries_ptr;
307        }
308        if (dyld_force_flat_namespace_ptr) {
309                *theCopyIter++ = dyld_force_flat_namespace_ptr;
310        }
311        if (darwintrace_log_ptr) {
312                *theCopyIter++ = darwintrace_log_ptr;
313        }
314
315        *theCopyIter = 0;
316       
317        return theCopy;
318}
319
320static void ask_for_filemap()
321{
322        filemap=exchange_with_port("filemap\t", sizeof("filemap\t"), 1, 0);
323        if((int)filemap==-1)
324                filemap=0;
325}
326
327inline void __darwintrace_setup() {
328#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
329#define close(x) syscall(SYS_close, (x))
330        if (__darwintrace_fd == -1) {
331                if (__env_darwintrace_log != NULL) {
332                        int olderrno = errno;
333                        int sock=socket(AF_UNIX, SOCK_STREAM, 0);
334                        struct sockaddr_un sun;
335                        sun.sun_family=AF_UNIX;
336                        strcpy(sun.sun_path, __env_darwintrace_log);
337                        if(connect(sock, (struct sockaddr*)&sun, strlen(__env_darwintrace_log)+1+sizeof(sun.sun_family))!=-1)
338                        {
339                                dprintf("darwintrace: connect successful. socket %d\n", sock);
340                                __darwintrace_fd=sock;
341                                ask_for_filemap();
342                        }else dprintf("connect failed %d :-(\n", errno);
343                        errno = olderrno;
344                }
345        }
346#undef close
347#undef open
348}
349
350/* log a call and optionally get the real path from the fd if it's not 0.
351 * op:                  the operation (open, readlink, execve)
352 * path:                the path of the file
353 * fd:                  a fd to the file, or 0 if we don't have any.
354 */
355inline void __darwintrace_log_op(const char* op, const char* path, int fd) {
356        int size;
357        char somepath[MAXPATHLEN];
358        char logbuffer[BUFFER_SIZE];
359       
360        do {
361#ifdef __APPLE__ /* Only Darwin has volfs and F_GETPATH */
362                if ((fd > 0) && (DARWINTRACE_LOG_FULL_PATH
363                        || (strncmp(path, "/.vol/", 6) == 0))) {
364                        if(fcntl(fd, F_GETPATH, somepath) == -1) {
365                                /* getpath failed. use somepath instead */
366                                strlcpy(somepath, path, sizeof(somepath));
367                                break;
368                        }
369                }
370#endif
371                if (path[0] != '/') {
372                        int len;
373                        (void) getcwd(somepath, sizeof(somepath));
374                        len = strlen(somepath);
375                        somepath[len++] = '/';
376                        strlcpy(&somepath[len], path, sizeof(somepath) - len);
377                        break;
378                }
379
380                /* otherwise, just copy the original path. */
381                strlcpy(somepath, path, sizeof(somepath));
382        } while (0);
383
384        /* clean the path. */
385        __darwintrace_cleanup_path(somepath);
386
387        size = snprintf(logbuffer, sizeof(logbuffer),
388                "%s\t%s",
389                op, somepath );
390
391        exchange_with_port(logbuffer, size+1, 0, 0);
392       
393        return;
394}
395
396/* remap resource fork access to the data fork.
397 * do a partial realpath(3) to fix "foo//bar" to "foo/bar"
398 */
399inline void __darwintrace_cleanup_path(char *path) {
400  size_t pathlen;
401#ifdef __APPLE__
402  size_t rsrclen;
403#endif
404  size_t i, shiftamount;
405  enum { SAWSLASH, NOTHING } state = NOTHING;
406
407  /* if this is a foo/..namedfork/rsrc, strip it off */
408  pathlen = strlen(path);
409  /* ..namedfork/rsrc is only on OS X */
410#ifdef __APPLE__
411  rsrclen = strlen(_PATH_RSRCFORKSPEC);
412  if(pathlen > rsrclen
413     && 0 == strcmp(path + pathlen - rsrclen,
414                    _PATH_RSRCFORKSPEC)) {
415    path[pathlen - rsrclen] = '\0';
416    pathlen -= rsrclen;
417  }
418#endif
419
420  /* for each position in string (including
421     terminal \0), check if we're in a run of
422     multiple slashes, and only emit the
423     first one
424  */
425  for(i=0, shiftamount=0; i <= pathlen; i++) {
426    if(state == SAWSLASH) {
427      if(path[i] == '/') {
428        /* consume it */
429        shiftamount++;
430      } else {
431        state = NOTHING;
432        path[i - shiftamount] = path[i];
433      }
434    } else {
435      if(path[i] == '/') {
436        state = SAWSLASH;
437      }
438      path[i - shiftamount] = path[i];
439    }
440  }
441
442  dprintf("darwintrace: cleanup resulted in %s\n", path);
443}
444
445/*
446 * return 1 if path is directory or not exists
447 * return 0 otherwise
448 */
449static int is_directory(const char * path)
450{
451#define stat(path, sb) syscall(SYS_stat, path, sb)
452        struct stat s;
453        if(stat(path, &s)==-1)
454                /* Actually is not directory, but anyway, we shouldn't test a dependency unless file exists */
455                return 1;
456       
457        return S_ISDIR(s.st_mode);
458#undef stat
459}
460
461
462/*
463 * return 1 if path allowed, 0 otherwise
464 */
465static int ask_for_dependency(char * path)
466{
467        char buffer[BUFFER_SIZE], *p;
468        int result=0;
469       
470        if(is_directory(path))
471                return 1;
472       
473        strcpy(buffer, "dep_check\t");
474        strcpy(buffer+10, path);
475        p=exchange_with_port(buffer, strlen(buffer)+1, 1, 0);
476        if((int)p==-1||!p)
477                return 0;
478       
479        if(*p=='+')
480                result=1;
481       
482        free(p);
483        return result;
484}
485
486/*
487 * exchange_with_port - routine to send/recv from/to socket
488 * Parameters:
489 *   buf      -- buffer with data to send
490 *   len      -- length of data
491 *   answer   -- 1 (yes, I want to receive answer) and 0 (no, thanks, just send)
492 *   failures -- should be setted 0 on external calls (avoid infinite recursion)
493 * Return value:
494 *    -1     -- something went wrong
495 *    0      -- data successfully sent
496 *    string -- answer (caller shoud free it)
497 */
498static char * exchange_with_port(const char * buf, size_t len, int answer, char failures)
499{
500        wait_for_socket(__darwintrace_fd, 1);
501        if(send(__darwintrace_fd, buf, len, 0)==-1)
502        {
503                if(errno==ENOTSOCK && failures<3)
504                {
505                        __darwintrace_fd=-1;
506                        __darwintrace_setup();
507                        return exchange_with_port(buf, len, answer, failures+1);
508                }
509                return (char*)-1;
510        }
511        if(!answer)
512                return 0;
513        {
514                size_t l=0;
515                char * b;
516               
517                wait_for_socket(__darwintrace_fd, 0);
518                recv(__darwintrace_fd, &l, sizeof(l),0);
519                if(!l)
520                        return 0;
521                b=(char*)malloc(l+1);
522                b[l]=0;
523                recv(__darwintrace_fd, b, l, 0);
524                return b;
525        }
526}
527
528/*
529 * return 1 if path (once normalized) is in sandbox or redirected, 0 otherwise.
530 */
531inline int __darwintrace_is_in_sandbox(const char* path, char * newpath) {
532        char * t, * p, * _;
533        int result=-1;
534       
535        __darwintrace_setup();
536       
537        if(!filemap)
538                return 1;
539       
540        if(*path=='/')
541                p=strdup(path);
542        else
543        {
544                p=(char*)malloc(BUFFER_SIZE);
545                (void) getcwd(p, BUFFER_SIZE-1);
546                _=p+strlen(p)+1;
547                if(_[-1]!='/')
548                        *_++='/';
549                strncpy(_, path, BUFFER_SIZE-(_-p));
550        }
551        __darwintrace_cleanup_path(p);
552                       
553        do
554        {
555                for(t=filemap; *t;)
556                {
557                        if(__darwintrace_strbeginswith(p, t))
558                        {
559                                t+=strlen(t)+1;
560                                switch(*t)
561                                {
562                                case 0:
563                                        result=1;
564                                        break;
565                                case 1:
566                                        if(!newpath)
567                                        {
568                                                result=0;
569                                                break;
570                                        }
571                                        strcpy(newpath, t+1);
572                                        _=newpath+strlen(newpath);
573                                        if(_[-1]!='/')
574                                                *_++='/';
575                                        strcpy(_, p);
576                                        result=1;
577                                        break;
578                                case 2:
579                                        result=ask_for_dependency(p);
580                                        break;
581                                }
582                        }
583                        if(result!=-1)
584                                break;
585                        t+=strlen(t)+1;
586                        if(*t==1)
587                                t+=strlen(t)+1;
588                        else
589                                t+=2;
590                }
591                if(result!=-1)
592                        break;
593                __darwintrace_log_op("sandbox_violation", path, 0);
594                result=0;
595        }
596        while(0);
597        free(p);
598        return result;
599}
600
601/* Log calls to open(2) into the file specified by DARWINTRACE_LOG.
602   Only logs if the DARWINTRACE_LOG environment variable is set.
603   Only logs files (or rather, do not logs directories)
604   Only logs files where the open succeeds.
605   Only logs files opened for read access, without the O_CREAT flag set
606        (unless DARWINTRACE_LOG_CREATE is set).
607   The assumption is that any file that can be created isn't necessary
608   to build the project.
609*/
610
611int open(const char* path, int flags, ...) {
612#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
613        mode_t mode;
614        int result;
615        va_list args;
616        struct stat sb;
617        char newpath[MAXPATHLEN];
618        int isInSandbox;       
619
620        /* Why mode here ? */
621        va_start(args, flags);
622        mode = va_arg(args, int);
623        va_end(args);
624       
625        result = 0;
626       
627        if((stat(path, &sb)!=-1 && !(sb.st_mode&S_IFDIR)) || flags & O_CREAT )
628        {
629                *newpath=0;
630                __darwintrace_setup();
631                isInSandbox = __darwintrace_is_in_sandbox(path, newpath);
632                if (isInSandbox == 0) {
633                        dprintf("darwintrace: creation/writing was forbidden at %s\n", path);
634                        errno = EACCES;
635                        result = -1;
636                }
637                if(*newpath)
638                        path=newpath;
639        }
640        if (result == 0) {
641                result = open(path, flags, mode);
642        }
643        return result;
644#undef open
645}
646
647/* Log calls to readlink(2) into the file specified by DARWINTRACE_LOG.
648   Only logs if the DARWINTRACE_LOG environment variable is set.
649   Only logs files where the readlink succeeds.
650*/
651#ifdef READLINK_IS_NOT_P1003_1A
652int  readlink(const char * path, char * buf, int bufsiz) {
653#else
654ssize_t  readlink(const char * path, char * buf, size_t bufsiz) {
655#endif
656#define readlink(x,y,z) syscall(SYS_readlink, (x), (y), (z))
657        ssize_t result;
658        int isInSandbox;
659
660        result = readlink(path, buf, bufsiz);
661        if (result >= 0) {
662                __darwintrace_setup();
663                isInSandbox = __darwintrace_is_in_sandbox(path, 0);
664                if (!isInSandbox)
665                {
666                        errno=EACCES;
667                        result=-1;
668                }
669        }
670        return result;
671#undef readlink
672}
673
674int execve(const char* path, char* const argv[], char* const envp[]) {
675#define __execve(x,y,z) syscall(SYS_execve, (x), (y), (z))
676#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
677#define close(x) syscall(SYS_close, (x))
678#define lstat(x, y) syscall(SYS_lstat, (x), (y))
679        int result;
680        __darwintrace_setup();
681        if (__darwintrace_fd >= 0) {
682          struct stat sb;
683          /* for symlinks, we want to capture
684           * both the original path and the modified one,
685           * since for /usr/bin/gcc -> gcc-4.0,
686           * both "gcc_select" and "gcc" are contributors
687           */
688          if (lstat(path, &sb) == 0) {
689                int fd;
690
691            if(S_ISLNK(sb.st_mode)) {
692              /* for symlinks, print both */
693                  __darwintrace_log_op("execve", path, 0);
694            }
695               
696                fd = open(path, O_RDONLY, 0);
697                if (fd > 0) {
698                  char buffer[MAXPATHLEN+1], newpath[MAXPATHLEN+1];
699                  ssize_t bytes_read;
700               
701                  *newpath=0;
702                  if(__darwintrace_is_in_sandbox(path, newpath)==0)
703                  {
704                        close(fd);
705                        errno=ENOENT;
706                    return -1;
707                  }
708                  if(*newpath)
709                    path=newpath;
710       
711                  /* once we have an open fd, if a full path was requested, do it */
712                  __darwintrace_log_op("execve", path, fd);
713
714                  /* read the file for the interpreter */
715                  bytes_read = read(fd, buffer, MAXPATHLEN);
716                  buffer[bytes_read] = 0;
717                  if (bytes_read > 2 &&
718                        buffer[0] == '#' && buffer[1] == '!') {
719                        const char* interp = &buffer[2];
720                        int i;
721                        /* skip past leading whitespace */
722                        for (i = 2; i < bytes_read; ++i) {
723                          if (buffer[i] != ' ' && buffer[i] != '\t') {
724                                interp = &buffer[i];
725                                break;
726                          }
727                        }
728                        /* found interpreter (or ran out of data)
729                           skip until next whitespace, then terminate the string */
730                        for (; i < bytes_read; ++i) {
731                          if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n') {
732                                buffer[i] = 0;
733                                break;
734                          }
735                        }
736                        /* we have liftoff */
737                        if (interp && interp[0] != '\0') {
738                          __darwintrace_log_op("execve", interp, 0);
739                        }
740                  }
741                  close(fd);
742                }
743          }
744        close(__darwintrace_fd);
745        __darwintrace_fd=-1;
746        }
747       
748        /* call the original execve function, but fix the environment if required. */
749        result = __execve(path, argv, __darwintrace_restore_env(envp));
750        return result;
751#undef lstat
752#undef close
753#undef open
754#undef execve
755}
756
757/* if darwintrace has been initialized, trap
758   attempts to close our file descriptor
759*/
760int close(int fd) {
761#define close(x) syscall(SYS_close, (x))
762
763  if(__darwintrace_fd != -2 && fd == __darwintrace_fd) {
764    errno = EBADF;
765    return -1;
766  }
767
768  return close(fd);
769#undef close
770}
771
772/* Trap attempts to unlink a file outside the sandbox.
773 */
774int unlink(const char* path) {
775#define __unlink(x) syscall(SYS_unlink, (x))
776        int result = 0;
777        int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
778        if (isInSandbox == 1) {
779                dprintf("darwintrace: unlink was allowed at %s\n", path);
780        } else if (isInSandbox == 0) {
781                /* outside sandbox, but sandbox is defined: forbid */
782                dprintf("darwintrace: unlink was forbidden at %s\n", path);
783                errno = EACCES;
784                result = -1;
785        }
786       
787        if (result == 0) {
788                result = __unlink(path);
789        }
790       
791        return result;
792}
793
794/* Trap attempts to create directories outside the sandbox.
795 */
796int mkdir(const char* path, mode_t mode) {
797#define __mkdir(x,y) syscall(SYS_mkdir, (x), (y))
798        int result = 0;
799        int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
800        if (isInSandbox == 1) {
801                dprintf("darwintrace: mkdir was allowed at %s\n", path);
802        } else if (isInSandbox == 0) {
803                /* outside sandbox, but sandbox is defined: forbid */
804                /* only consider directories that do not exist. */
805                struct stat theInfo;
806                int err;
807                err = lstat(path, &theInfo);
808                if ((err == -1) && (errno == ENOENT))
809                {
810                        dprintf("darwintrace: mkdir was forbidden at %s\n", path);
811                        errno = EACCES;
812                        result = -1;
813                } /* otherwise, mkdir will do nothing (directory exists) or fail
814                     (another error) */
815        }
816       
817        if (result == 0) {
818                result = __mkdir(path, mode);
819        }
820       
821        return result;
822}
823
824/* Trap attempts to remove directories outside the sandbox.
825 */
826int rmdir(const char* path) {
827#define __rmdir(x) syscall(SYS_rmdir, (x))
828        int result = 0;
829        int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
830        if (isInSandbox == 1) {
831                dprintf("darwintrace: rmdir was allowed at %s\n", path);
832        } else if (isInSandbox == 0) {
833                /* outside sandbox, but sandbox is defined: forbid */
834                dprintf("darwintrace: removing directory %s was forbidden\n", path);
835                errno = EACCES;
836                result = -1;
837        }
838       
839        if (result == 0) {
840                result = __rmdir(path);
841        }
842       
843        return result;
844}
845
846/* Trap attempts to rename files/directories outside the sandbox.
847 */
848int rename(const char* from, const char* to) {
849#define __rename(x,y) syscall(SYS_rename, (x), (y))
850        int result = 0;
851        int isInSandbox = __darwintrace_is_in_sandbox(from, 0);
852        if (isInSandbox == 1) {
853                dprintf("darwintrace: rename was allowed at %s\n", from);
854        } else if (isInSandbox == 0) {
855                /* outside sandbox, but sandbox is defined: forbid */
856                dprintf("darwintrace: renaming from %s was forbidden\n", from);
857                errno = EACCES;
858                result = -1;
859        }
860
861        if (result == 0) {
862                isInSandbox = __darwintrace_is_in_sandbox(to, 0);
863                if (isInSandbox == 1) {
864                        dprintf("darwintrace: rename was allowed at %s\n", to);
865                } else if (isInSandbox == 0) {
866                        /* outside sandbox, but sandbox is defined: forbid */
867                        dprintf("darwintrace: renaming to %s was forbidden\n", to);
868                        errno = EACCES;
869                        result = -1;
870                }
871        }
872       
873        if (result == 0) {
874                result = __rename(from, to);
875        }
876       
877        return result;
878}
879
880int stat(const char * path, struct stat * sb)
881{
882#define stat(path, sb) syscall(SYS_stat, path, sb)
883        int result=0;
884        char newpath[260];
885               
886        *newpath=0;
887        if(!is_directory(path)&&__darwintrace_is_in_sandbox(path, newpath)==0)
888        {
889                errno=ENOENT;
890                result=-1;
891        }else
892        {
893                if(*newpath)
894                        path=newpath;
895                       
896                result=stat(path, sb);
897        }
898       
899        return result;
900#undef stat
901}
902
903int lstat(const char * path, struct stat * sb)
904{
905#define stat(path, sb) syscall(SYS_lstat, path, sb)
906        int result=0;
907        char newpath[260];
908       
909        *newpath=0;
910        if(!is_directory(path)&&__darwintrace_is_in_sandbox(path, newpath)==0)
911        {
912                errno=ENOENT;
913                result=-1;
914        }else
915        {
916                if(*newpath)
917                        path=newpath;
918                       
919                result=stat(path, sb);
920        }
921       
922        return result;
923#undef stat
924}
Note: See TracBrowser for help on using the repository browser.