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

Last change on this file since 50702 was 50702, checked in by toby@…, 11 years ago

compile with clang

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.7 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 50702 2009-05-07 08:59:20Z toby@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(filemap==(char*)-1)
324                filemap=0;
325}
326
327__attribute__((always_inline))
328inline void __darwintrace_setup() {
329#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
330#define close(x) syscall(SYS_close, (x))
331        if (__darwintrace_fd == -1) {
332                if (__env_darwintrace_log != NULL) {
333                        int olderrno = errno;
334                        int sock=socket(AF_UNIX, SOCK_STREAM, 0);
335                        struct sockaddr_un sun;
336                        sun.sun_family=AF_UNIX;
337                        strcpy(sun.sun_path, __env_darwintrace_log);
338                        if(connect(sock, (struct sockaddr*)&sun, strlen(__env_darwintrace_log)+1+sizeof(sun.sun_family))!=-1)
339                        {
340                                dprintf("darwintrace: connect successful. socket %d\n", sock);
341                                __darwintrace_fd=sock;
342                                ask_for_filemap();
343                        } else {
344                                dprintf("connect failed %d :-(\n", errno);
345                        }
346                        errno = olderrno;
347                }
348        }
349#undef close
350#undef open
351}
352
353/* log a call and optionally get the real path from the fd if it's not 0.
354 * op:                  the operation (open, readlink, execve)
355 * path:                the path of the file
356 * fd:                  a fd to the file, or 0 if we don't have any.
357 */
358__attribute__((always_inline))
359inline void __darwintrace_log_op(const char* op, const char* path, int fd) {
360        int size;
361        char somepath[MAXPATHLEN];
362        char logbuffer[BUFFER_SIZE];
363       
364        do {
365#ifdef __APPLE__ /* Only Darwin has volfs and F_GETPATH */
366                if ((fd > 0) && (DARWINTRACE_LOG_FULL_PATH
367                        || (strncmp(path, "/.vol/", 6) == 0))) {
368                        if(fcntl(fd, F_GETPATH, somepath) == -1) {
369                                /* getpath failed. use somepath instead */
370                                strlcpy(somepath, path, sizeof(somepath));
371                                break;
372                        }
373                }
374#endif
375                if (path[0] != '/') {
376                        int len;
377                        (void) getcwd(somepath, sizeof(somepath));
378                        len = strlen(somepath);
379                        somepath[len++] = '/';
380                        strlcpy(&somepath[len], path, sizeof(somepath) - len);
381                        break;
382                }
383
384                /* otherwise, just copy the original path. */
385                strlcpy(somepath, path, sizeof(somepath));
386        } while (0);
387
388        /* clean the path. */
389        __darwintrace_cleanup_path(somepath);
390
391        size = snprintf(logbuffer, sizeof(logbuffer),
392                "%s\t%s",
393                op, somepath );
394
395        exchange_with_port(logbuffer, size+1, 0, 0);
396       
397        return;
398}
399
400/* remap resource fork access to the data fork.
401 * do a partial realpath(3) to fix "foo//bar" to "foo/bar"
402 */
403inline void __darwintrace_cleanup_path(char *path) {
404  size_t pathlen;
405#ifdef __APPLE__
406  size_t rsrclen;
407#endif
408  size_t i, shiftamount;
409  enum { SAWSLASH, NOTHING } state = NOTHING;
410
411  /* if this is a foo/..namedfork/rsrc, strip it off */
412  pathlen = strlen(path);
413  /* ..namedfork/rsrc is only on OS X */
414#ifdef __APPLE__
415  rsrclen = strlen(_PATH_RSRCFORKSPEC);
416  if(pathlen > rsrclen
417     && 0 == strcmp(path + pathlen - rsrclen,
418                    _PATH_RSRCFORKSPEC)) {
419    path[pathlen - rsrclen] = '\0';
420    pathlen -= rsrclen;
421  }
422#endif
423
424  /* for each position in string (including
425     terminal \0), check if we're in a run of
426     multiple slashes, and only emit the
427     first one
428  */
429  for(i=0, shiftamount=0; i <= pathlen; i++) {
430    if(state == SAWSLASH) {
431      if(path[i] == '/') {
432        /* consume it */
433        shiftamount++;
434      } else {
435        state = NOTHING;
436        path[i - shiftamount] = path[i];
437      }
438    } else {
439      if(path[i] == '/') {
440        state = SAWSLASH;
441      }
442      path[i - shiftamount] = path[i];
443    }
444  }
445
446  dprintf("darwintrace: cleanup resulted in %s\n", path);
447}
448
449/*
450 * return 1 if path is directory or not exists
451 * return 0 otherwise
452 */
453static int is_directory(const char * path)
454{
455#define stat(path, sb) syscall(SYS_stat, path, sb)
456        struct stat s;
457        if(stat(path, &s)==-1)
458                /* Actually is not directory, but anyway, we shouldn't test a dependency unless file exists */
459                return 1;
460       
461        return S_ISDIR(s.st_mode);
462#undef stat
463}
464
465
466/*
467 * return 1 if path allowed, 0 otherwise
468 */
469static int ask_for_dependency(char * path)
470{
471        char buffer[BUFFER_SIZE], *p;
472        int result=0;
473       
474        if(is_directory(path))
475                return 1;
476       
477        strcpy(buffer, "dep_check\t");
478        strcpy(buffer+10, path);
479        p=exchange_with_port(buffer, strlen(buffer)+1, 1, 0);
480        if(p==(char*)-1||!p)
481                return 0;
482       
483        if(*p=='+')
484                result=1;
485       
486        free(p);
487        return result;
488}
489
490/*
491 * exchange_with_port - routine to send/recv from/to socket
492 * Parameters:
493 *   buf      -- buffer with data to send
494 *   len      -- length of data
495 *   answer   -- 1 (yes, I want to receive answer) and 0 (no, thanks, just send)
496 *   failures -- should be setted 0 on external calls (avoid infinite recursion)
497 * Return value:
498 *    -1     -- something went wrong
499 *    0      -- data successfully sent
500 *    string -- answer (caller shoud free it)
501 */
502static char * exchange_with_port(const char * buf, size_t len, int answer, char failures)
503{
504        wait_for_socket(__darwintrace_fd, 1);
505        if(send(__darwintrace_fd, buf, len, 0)==-1)
506        {
507                if(errno==ENOTSOCK && failures<3)
508                {
509                        __darwintrace_fd=-1;
510                        __darwintrace_setup();
511                        return exchange_with_port(buf, len, answer, failures+1);
512                }
513                return (char*)-1;
514        }
515        if(!answer)
516                return 0;
517        {
518                size_t l=0;
519                char * b;
520               
521                wait_for_socket(__darwintrace_fd, 0);
522                recv(__darwintrace_fd, &l, sizeof(l),0);
523                if(!l)
524                        return 0;
525                b=(char*)malloc(l+1);
526                b[l]=0;
527                recv(__darwintrace_fd, b, l, 0);
528                return b;
529        }
530}
531
532/*
533 * return 1 if path (once normalized) is in sandbox or redirected, 0 otherwise.
534 */
535__attribute__((always_inline))
536inline int __darwintrace_is_in_sandbox(const char* path, char * newpath) {
537        char * t, * p, * _;
538        int result=-1;
539       
540        __darwintrace_setup();
541       
542        if(!filemap)
543                return 1;
544       
545        if(*path=='/')
546                p=strdup(path);
547        else
548        {
549                p=(char*)malloc(BUFFER_SIZE);
550                (void) getcwd(p, BUFFER_SIZE-1);
551                _=p+strlen(p)+1;
552                if(_[-1]!='/')
553                        *_++='/';
554                strncpy(_, path, BUFFER_SIZE-(_-p));
555        }
556        __darwintrace_cleanup_path(p);
557                       
558        do
559        {
560                for(t=filemap; *t;)
561                {
562                        if(__darwintrace_strbeginswith(p, t))
563                        {
564                                t+=strlen(t)+1;
565                                switch(*t)
566                                {
567                                case 0:
568                                        result=1;
569                                        break;
570                                case 1:
571                                        if(!newpath)
572                                        {
573                                                result=0;
574                                                break;
575                                        }
576                                        strcpy(newpath, t+1);
577                                        _=newpath+strlen(newpath);
578                                        if(_[-1]!='/')
579                                                *_++='/';
580                                        strcpy(_, p);
581                                        result=1;
582                                        break;
583                                case 2:
584                                        result=ask_for_dependency(p);
585                                        break;
586                                }
587                        }
588                        if(result!=-1)
589                                break;
590                        t+=strlen(t)+1;
591                        if(*t==1)
592                                t+=strlen(t)+1;
593                        else
594                                t+=2;
595                }
596                if(result!=-1)
597                        break;
598                __darwintrace_log_op("sandbox_violation", path, 0);
599                result=0;
600        }
601        while(0);
602        free(p);
603        return result;
604}
605
606/* Log calls to open(2) into the file specified by DARWINTRACE_LOG.
607   Only logs if the DARWINTRACE_LOG environment variable is set.
608   Only logs files (or rather, do not logs directories)
609   Only logs files where the open succeeds.
610   Only logs files opened for read access, without the O_CREAT flag set
611        (unless DARWINTRACE_LOG_CREATE is set).
612   The assumption is that any file that can be created isn't necessary
613   to build the project.
614*/
615
616int open(const char* path, int flags, ...) {
617#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
618        mode_t mode;
619        int result;
620        va_list args;
621        struct stat sb;
622        char newpath[MAXPATHLEN];
623        int isInSandbox;       
624
625        /* Why mode here ? */
626        va_start(args, flags);
627        mode = va_arg(args, int);
628        va_end(args);
629       
630        result = 0;
631       
632        if((stat(path, &sb)!=-1 && !(sb.st_mode&S_IFDIR)) || flags & O_CREAT )
633        {
634                *newpath=0;
635                __darwintrace_setup();
636                isInSandbox = __darwintrace_is_in_sandbox(path, newpath);
637                if (isInSandbox == 0) {
638                        dprintf("darwintrace: creation/writing was forbidden at %s\n", path);
639                        errno = EACCES;
640                        result = -1;
641                }
642                if(*newpath)
643                        path=newpath;
644        }
645        if (result == 0) {
646                result = open(path, flags, mode);
647        }
648        return result;
649#undef open
650}
651
652/* Log calls to readlink(2) into the file specified by DARWINTRACE_LOG.
653   Only logs if the DARWINTRACE_LOG environment variable is set.
654   Only logs files where the readlink succeeds.
655*/
656#ifdef READLINK_IS_NOT_P1003_1A
657int  readlink(const char * path, char * buf, int bufsiz) {
658#else
659ssize_t  readlink(const char * path, char * buf, size_t bufsiz) {
660#endif
661#define readlink(x,y,z) syscall(SYS_readlink, (x), (y), (z))
662        ssize_t result;
663        int isInSandbox;
664
665        result = readlink(path, buf, bufsiz);
666        if (result >= 0) {
667                __darwintrace_setup();
668                isInSandbox = __darwintrace_is_in_sandbox(path, 0);
669                if (!isInSandbox)
670                {
671                        errno=EACCES;
672                        result=-1;
673                }
674        }
675        return result;
676#undef readlink
677}
678
679int execve(const char* path, char* const argv[], char* const envp[]) {
680#define __execve(x,y,z) syscall(SYS_execve, (x), (y), (z))
681#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
682#define close(x) syscall(SYS_close, (x))
683#define lstat(x, y) syscall(SYS_lstat, (x), (y))
684        int result;
685        __darwintrace_setup();
686        if (__darwintrace_fd >= 0) {
687          struct stat sb;
688          /* for symlinks, we want to capture
689           * both the original path and the modified one,
690           * since for /usr/bin/gcc -> gcc-4.0,
691           * both "gcc_select" and "gcc" are contributors
692           */
693          if (lstat(path, &sb) == 0) {
694                int fd;
695
696            if(S_ISLNK(sb.st_mode)) {
697              /* for symlinks, print both */
698                  __darwintrace_log_op("execve", path, 0);
699            }
700               
701                fd = open(path, O_RDONLY, 0);
702                if (fd > 0) {
703                  char buffer[MAXPATHLEN+1], newpath[MAXPATHLEN+1];
704                  ssize_t bytes_read;
705               
706                  *newpath=0;
707                  if(__darwintrace_is_in_sandbox(path, newpath)==0)
708                  {
709                        close(fd);
710                        errno=ENOENT;
711                    return -1;
712                  }
713                  if(*newpath)
714                    path=newpath;
715       
716                  /* once we have an open fd, if a full path was requested, do it */
717                  __darwintrace_log_op("execve", path, fd);
718
719                  /* read the file for the interpreter */
720                  bytes_read = read(fd, buffer, MAXPATHLEN);
721                  buffer[bytes_read] = 0;
722                  if (bytes_read > 2 &&
723                        buffer[0] == '#' && buffer[1] == '!') {
724                        const char* interp = &buffer[2];
725                        int i;
726                        /* skip past leading whitespace */
727                        for (i = 2; i < bytes_read; ++i) {
728                          if (buffer[i] != ' ' && buffer[i] != '\t') {
729                                interp = &buffer[i];
730                                break;
731                          }
732                        }
733                        /* found interpreter (or ran out of data)
734                           skip until next whitespace, then terminate the string */
735                        for (; i < bytes_read; ++i) {
736                          if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n') {
737                                buffer[i] = 0;
738                                break;
739                          }
740                        }
741                        /* we have liftoff */
742                        if (interp && interp[0] != '\0') {
743                          __darwintrace_log_op("execve", interp, 0);
744                        }
745                  }
746                  close(fd);
747                }
748          }
749        close(__darwintrace_fd);
750        __darwintrace_fd=-1;
751        }
752       
753        /* call the original execve function, but fix the environment if required. */
754        result = __execve(path, argv, __darwintrace_restore_env(envp));
755        return result;
756#undef lstat
757#undef close
758#undef open
759#undef execve
760}
761
762/* if darwintrace has been initialized, trap
763   attempts to close our file descriptor
764*/
765int close(int fd) {
766#define close(x) syscall(SYS_close, (x))
767
768  if(__darwintrace_fd != -2 && fd == __darwintrace_fd) {
769    errno = EBADF;
770    return -1;
771  }
772
773  return close(fd);
774#undef close
775}
776
777/* Trap attempts to unlink a file outside the sandbox.
778 */
779int unlink(const char* path) {
780#define __unlink(x) syscall(SYS_unlink, (x))
781        int result = 0;
782        int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
783        if (isInSandbox == 1) {
784                dprintf("darwintrace: unlink was allowed at %s\n", path);
785        } else if (isInSandbox == 0) {
786                /* outside sandbox, but sandbox is defined: forbid */
787                dprintf("darwintrace: unlink was forbidden at %s\n", path);
788                errno = EACCES;
789                result = -1;
790        }
791       
792        if (result == 0) {
793                result = __unlink(path);
794        }
795       
796        return result;
797}
798
799/* Trap attempts to create directories outside the sandbox.
800 */
801int mkdir(const char* path, mode_t mode) {
802#define __mkdir(x,y) syscall(SYS_mkdir, (x), (y))
803        int result = 0;
804        int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
805        if (isInSandbox == 1) {
806                dprintf("darwintrace: mkdir was allowed at %s\n", path);
807        } else if (isInSandbox == 0) {
808                /* outside sandbox, but sandbox is defined: forbid */
809                /* only consider directories that do not exist. */
810                struct stat theInfo;
811                int err;
812                err = lstat(path, &theInfo);
813                if ((err == -1) && (errno == ENOENT))
814                {
815                        dprintf("darwintrace: mkdir was forbidden at %s\n", path);
816                        errno = EACCES;
817                        result = -1;
818                } /* otherwise, mkdir will do nothing (directory exists) or fail
819                     (another error) */
820        }
821       
822        if (result == 0) {
823                result = __mkdir(path, mode);
824        }
825       
826        return result;
827}
828
829/* Trap attempts to remove directories outside the sandbox.
830 */
831int rmdir(const char* path) {
832#define __rmdir(x) syscall(SYS_rmdir, (x))
833        int result = 0;
834        int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
835        if (isInSandbox == 1) {
836                dprintf("darwintrace: rmdir was allowed at %s\n", path);
837        } else if (isInSandbox == 0) {
838                /* outside sandbox, but sandbox is defined: forbid */
839                dprintf("darwintrace: removing directory %s was forbidden\n", path);
840                errno = EACCES;
841                result = -1;
842        }
843       
844        if (result == 0) {
845                result = __rmdir(path);
846        }
847       
848        return result;
849}
850
851/* Trap attempts to rename files/directories outside the sandbox.
852 */
853int rename(const char* from, const char* to) {
854#define __rename(x,y) syscall(SYS_rename, (x), (y))
855        int result = 0;
856        int isInSandbox = __darwintrace_is_in_sandbox(from, 0);
857        if (isInSandbox == 1) {
858                dprintf("darwintrace: rename was allowed at %s\n", from);
859        } else if (isInSandbox == 0) {
860                /* outside sandbox, but sandbox is defined: forbid */
861                dprintf("darwintrace: renaming from %s was forbidden\n", from);
862                errno = EACCES;
863                result = -1;
864        }
865
866        if (result == 0) {
867                isInSandbox = __darwintrace_is_in_sandbox(to, 0);
868                if (isInSandbox == 1) {
869                        dprintf("darwintrace: rename was allowed at %s\n", to);
870                } else if (isInSandbox == 0) {
871                        /* outside sandbox, but sandbox is defined: forbid */
872                        dprintf("darwintrace: renaming to %s was forbidden\n", to);
873                        errno = EACCES;
874                        result = -1;
875                }
876        }
877       
878        if (result == 0) {
879                result = __rename(from, to);
880        }
881       
882        return result;
883}
884
885int stat(const char * path, struct stat * sb)
886{
887#define stat(path, sb) syscall(SYS_stat, path, sb)
888        int result=0;
889        char newpath[260];
890               
891        *newpath=0;
892        if(!is_directory(path)&&__darwintrace_is_in_sandbox(path, newpath)==0)
893        {
894                errno=ENOENT;
895                result=-1;
896        }else
897        {
898                if(*newpath)
899                        path=newpath;
900                       
901                result=stat(path, sb);
902        }
903       
904        return result;
905#undef stat
906}
907
908int lstat(const char * path, struct stat * sb)
909{
910#define stat(path, sb) syscall(SYS_lstat, path, sb)
911        int result=0;
912        char newpath[260];
913       
914        *newpath=0;
915        if(!is_directory(path)&&__darwintrace_is_in_sandbox(path, newpath)==0)
916        {
917                errno=ENOENT;
918                result=-1;
919        }else
920        {
921                if(*newpath)
922                        path=newpath;
923                       
924                result=stat(path, sb);
925        }
926       
927        return result;
928#undef stat
929}
Note: See TracBrowser for help on using the repository browser.