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

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

Port trace: dep check, SDK redirect

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.3 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 28091 2007-08-20 14:48:10Z 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);
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);
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);
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        strcat(buffer, path);
475        p=exchange_with_port(buffer, strlen(buffer)+1, 1);
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 * Return value:
493 *    -1     -- something went wrong
494 *    0      -- data successfully sent
495 *    string -- answer (caller shoud free it)
496 */
497static char * exchange_with_port(const char * buf, size_t len, int answer)
498{
499        wait_for_socket(__darwintrace_fd, 1);
500        if(send(__darwintrace_fd, buf, len, 0)==-1)
501                return (char*)-1;
502        if(!answer)
503                return 0;
504        {
505                size_t l=0;
506                char * b;
507               
508                wait_for_socket(__darwintrace_fd, 0);
509                recv(__darwintrace_fd, &l, sizeof(l),0);
510                if(!l)
511                        return 0;
512                b=(char*)malloc(l+1);
513                b[l]=0;
514                recv(__darwintrace_fd, b, l, 0);
515                return b;
516        }
517}
518
519/*
520 * return 1 if path (once normalized) is in sandbox or redirected, 0 otherwise.
521 */
522inline int __darwintrace_is_in_sandbox(const char* path, char * newpath) {
523        char * t, * p, * _;
524        int result=-1;
525       
526        __darwintrace_setup();
527       
528        if(!filemap)
529                return 1;
530       
531        if(*path=='/')
532                p=strdup(path);
533        else
534        {
535                p=(char*)malloc(BUFFER_SIZE);
536                (void) getcwd(p, BUFFER_SIZE-1);
537                _=p+strlen(p)+1;
538                if(_[-1]!='/')
539                        *_++='/';
540                strncpy(_, path, BUFFER_SIZE-(_-p));
541        }
542        __darwintrace_cleanup_path(p);
543                       
544        do
545        {
546                for(t=filemap; *t;)
547                {
548                        if(__darwintrace_strbeginswith(p, t))
549                        {
550                                t+=strlen(t)+1;
551                                switch(*t)
552                                {
553                                case 0:
554                                        result=1;
555                                        break;
556                                case 1:
557                                        if(!newpath)
558                                        {
559                                                result=0;
560                                                break;
561                                        }
562                                        strcpy(newpath, t+1);
563                                        _=newpath+strlen(newpath);
564                                        if(_[-1]!='/')
565                                                *_++='/';
566                                        strcpy(_, p);
567                                        result=1;
568                                        break;
569                                case 2:
570                                        result=ask_for_dependency(p);
571                                        break;
572                                }
573                        }
574                        if(result!=-1)
575                                break;
576                        t+=strlen(t)+1;
577                        if(*t==1)
578                                t+=strlen(t)+1;
579                        else
580                                t+=2;
581                }
582                if(result!=-1)
583                        break;
584                __darwintrace_log_op("sandbox_violation", path, 0);
585                result=0;
586        }
587        while(0);
588        free(p);
589        return result;
590}
591
592/* Log calls to open(2) into the file specified by DARWINTRACE_LOG.
593   Only logs if the DARWINTRACE_LOG environment variable is set.
594   Only logs files (or rather, do not logs directories)
595   Only logs files where the open succeeds.
596   Only logs files opened for read access, without the O_CREAT flag set
597        (unless DARWINTRACE_LOG_CREATE is set).
598   The assumption is that any file that can be created isn't necessary
599   to build the project.
600*/
601
602int open(const char* path, int flags, ...) {
603#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
604        mode_t mode;
605        int result;
606        va_list args;
607        struct stat sb;
608        char newpath[MAXPATHLEN];
609        int isInSandbox;       
610
611        /* Why mode here ? */
612        va_start(args, flags);
613        mode = va_arg(args, int);
614        va_end(args);
615       
616        result = 0;
617       
618        if((stat(path, &sb)!=-1 && !(sb.st_mode&S_IFDIR)) || flags & O_CREAT )
619        {
620                *newpath=0;
621                __darwintrace_setup();
622                isInSandbox = __darwintrace_is_in_sandbox(path, newpath);
623                if (isInSandbox == 0) {
624                        dprintf("darwintrace: creation/writing was forbidden at %s\n", path);
625                        errno = EACCES;
626                        result = -1;
627                }
628                if(*newpath)
629                        path=newpath;
630        }
631        if (result == 0) {
632                result = open(path, flags, mode);
633        }
634        return result;
635#undef open
636}
637
638/* Log calls to readlink(2) into the file specified by DARWINTRACE_LOG.
639   Only logs if the DARWINTRACE_LOG environment variable is set.
640   Only logs files where the readlink succeeds.
641*/
642#ifdef READLINK_IS_NOT_P1003_1A
643int  readlink(const char * path, char * buf, int bufsiz) {
644#else
645ssize_t  readlink(const char * path, char * buf, size_t bufsiz) {
646#endif
647#define readlink(x,y,z) syscall(SYS_readlink, (x), (y), (z))
648        ssize_t result;
649        int isInSandbox;
650
651        result = readlink(path, buf, bufsiz);
652        if (result >= 0) {
653                __darwintrace_setup();
654                isInSandbox = __darwintrace_is_in_sandbox(path, 0);
655                if (!isInSandbox)
656                {
657                        errno=EACCES;
658                        result=-1;
659                }
660        }
661        return result;
662#undef readlink
663}
664
665int execve(const char* path, char* const argv[], char* const envp[]) {
666#define __execve(x,y,z) syscall(SYS_execve, (x), (y), (z))
667#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
668#define close(x) syscall(SYS_close, (x))
669#define lstat(x, y) syscall(SYS_lstat, (x), (y))
670        int result;
671        __darwintrace_setup();
672        if (__darwintrace_fd >= 0) {
673          struct stat sb;
674          /* for symlinks, we want to capture
675           * both the original path and the modified one,
676           * since for /usr/bin/gcc -> gcc-4.0,
677           * both "gcc_select" and "gcc" are contributors
678           */
679          if (lstat(path, &sb) == 0) {
680                int fd;
681
682            if(S_ISLNK(sb.st_mode)) {
683              /* for symlinks, print both */
684                  __darwintrace_log_op("execve", path, 0);
685            }
686               
687                fd = open(path, O_RDONLY, 0);
688                if (fd > 0) {
689                  char buffer[MAXPATHLEN+1], newpath[MAXPATHLEN+1];
690                  ssize_t bytes_read;
691               
692                  *newpath=0;
693                  if(__darwintrace_is_in_sandbox(path, newpath)==0)
694                  {
695                        close(fd);
696                        errno=ENOENT;
697                    return -1;
698                  }
699                  if(*newpath)
700                    path=newpath;
701       
702                  /* once we have an open fd, if a full path was requested, do it */
703                  __darwintrace_log_op("execve", path, fd);
704
705                  /* read the file for the interpreter */
706                  bytes_read = read(fd, buffer, MAXPATHLEN);
707                  buffer[bytes_read] = 0;
708                  if (bytes_read > 2 &&
709                        buffer[0] == '#' && buffer[1] == '!') {
710                        const char* interp = &buffer[2];
711                        int i;
712                        /* skip past leading whitespace */
713                        for (i = 2; i < bytes_read; ++i) {
714                          if (buffer[i] != ' ' && buffer[i] != '\t') {
715                                interp = &buffer[i];
716                                break;
717                          }
718                        }
719                        /* found interpreter (or ran out of data)
720                           skip until next whitespace, then terminate the string */
721                        for (; i < bytes_read; ++i) {
722                          if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n') {
723                                buffer[i] = 0;
724                                break;
725                          }
726                        }
727                        /* we have liftoff */
728                        if (interp && interp[0] != '\0') {
729                          __darwintrace_log_op("execve", interp, 0);
730                        }
731                  }
732                  close(fd);
733                }
734          }
735        close(__darwintrace_fd);
736        __darwintrace_fd=-1;
737        }
738       
739        /* call the original execve function, but fix the environment if required. */
740        result = __execve(path, argv, __darwintrace_restore_env(envp));
741        return result;
742#undef lstat
743#undef close
744#undef open
745#undef execve
746}
747
748/* if darwintrace has been initialized, trap
749   attempts to close our file descriptor
750*/
751int close(int fd) {
752#define close(x) syscall(SYS_close, (x))
753
754  if(__darwintrace_fd != -2 && fd == __darwintrace_fd) {
755    errno = EBADF;
756    return -1;
757  }
758
759  return close(fd);
760#undef close
761}
762
763/* Trap attempts to unlink a file outside the sandbox.
764 */
765int unlink(const char* path) {
766#define __unlink(x) syscall(SYS_unlink, (x))
767        int result = 0;
768        int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
769        if (isInSandbox == 1) {
770                dprintf("darwintrace: unlink was allowed at %s\n", path);
771        } else if (isInSandbox == 0) {
772                /* outside sandbox, but sandbox is defined: forbid */
773                dprintf("darwintrace: unlink was forbidden at %s\n", path);
774                errno = EACCES;
775                result = -1;
776        }
777       
778        if (result == 0) {
779                result = __unlink(path);
780        }
781       
782        return result;
783}
784
785/* Trap attempts to create directories outside the sandbox.
786 */
787int mkdir(const char* path, mode_t mode) {
788#define __mkdir(x,y) syscall(SYS_mkdir, (x), (y))
789        int result = 0;
790        int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
791        if (isInSandbox == 1) {
792                dprintf("darwintrace: mkdir was allowed at %s\n", path);
793        } else if (isInSandbox == 0) {
794                /* outside sandbox, but sandbox is defined: forbid */
795                /* only consider directories that do not exist. */
796                struct stat theInfo;
797                int err;
798                err = lstat(path, &theInfo);
799                if ((err == -1) && (errno == ENOENT))
800                {
801                        dprintf("darwintrace: mkdir was forbidden at %s\n", path);
802                        errno = EACCES;
803                        result = -1;
804                } /* otherwise, mkdir will do nothing (directory exists) or fail
805                     (another error) */
806        }
807       
808        if (result == 0) {
809                result = __mkdir(path, mode);
810        }
811       
812        return result;
813}
814
815/* Trap attempts to remove directories outside the sandbox.
816 */
817int rmdir(const char* path) {
818#define __rmdir(x) syscall(SYS_rmdir, (x))
819        int result = 0;
820        int isInSandbox = __darwintrace_is_in_sandbox(path, 0);
821        if (isInSandbox == 1) {
822                dprintf("darwintrace: rmdir was allowed at %s\n", path);
823        } else if (isInSandbox == 0) {
824                /* outside sandbox, but sandbox is defined: forbid */
825                dprintf("darwintrace: removing directory %s was forbidden\n", path);
826                errno = EACCES;
827                result = -1;
828        }
829       
830        if (result == 0) {
831                result = __rmdir(path);
832        }
833       
834        return result;
835}
836
837/* Trap attempts to rename files/directories outside the sandbox.
838 */
839int rename(const char* from, const char* to) {
840#define __rename(x,y) syscall(SYS_rename, (x), (y))
841        int result = 0;
842        int isInSandbox = __darwintrace_is_in_sandbox(from, 0);
843        if (isInSandbox == 1) {
844                dprintf("darwintrace: rename was allowed at %s\n", from);
845        } else if (isInSandbox == 0) {
846                /* outside sandbox, but sandbox is defined: forbid */
847                dprintf("darwintrace: renaming from %s was forbidden\n", from);
848                errno = EACCES;
849                result = -1;
850        }
851
852        if (result == 0) {
853                isInSandbox = __darwintrace_is_in_sandbox(to, 0);
854                if (isInSandbox == 1) {
855                        dprintf("darwintrace: rename was allowed at %s\n", to);
856                } else if (isInSandbox == 0) {
857                        /* outside sandbox, but sandbox is defined: forbid */
858                        dprintf("darwintrace: renaming to %s was forbidden\n", to);
859                        errno = EACCES;
860                        result = -1;
861                }
862        }
863       
864        if (result == 0) {
865                result = __rename(from, to);
866        }
867       
868        return result;
869}
870
871int stat(const char * path, struct stat * sb)
872{
873#define stat(path, sb) syscall(SYS_stat, path, sb)
874        int result=0;
875        char newpath[260];
876               
877        *newpath=0;
878        if(!is_directory(path)&&__darwintrace_is_in_sandbox(path, newpath)==0)
879        {
880                errno=ENOENT;
881                result=-1;
882        }else
883        {
884                if(*newpath)
885                        path=newpath;
886                       
887                result=stat(path, sb);
888        }
889       
890        return result;
891#undef stat
892}
893
894int lstat(const char * path, struct stat * sb)
895{
896#define stat(path, sb) syscall(SYS_lstat, path, sb)
897        int result=0;
898        char newpath[260];
899       
900        *newpath=0;
901        if(!is_directory(path)&&__darwintrace_is_in_sandbox(path, newpath)==0)
902        {
903                errno=ENOENT;
904                result=-1;
905        }else
906        {
907                if(*newpath)
908                        path=newpath;
909                       
910                result=stat(path, sb);
911        }
912       
913        return result;
914#undef stat
915}
Note: See TracBrowser for help on using the repository browser.