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

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

error checking, sprintf -> snprintf, strcpy -> strncpy

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