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

Last change on this file since 19004 was 19004, checked in by pguyot (Paul Guyot), 14 years ago

Changes to strengthen the trace mode:

  • the values of the global variables are noted when the library is loaded and not when the first trapped function is called.
  • when a process calls exec[ve], the environment variables are restored.

Both changes aim at preventing processes to (inadvertantly) bypass of trace
mode.

Several holes remain (syscall, setuid binaries owned by a different user, kernel
modules), but this should prevent all inadvertant methods to bypass the trace
mode.

  • Property svn:eol-style set to native
File size: 23.1 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,v 1.21 2006/08/04 06:40:41 pguyot Exp $
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
61#ifndef HAVE_STRLCPY
62/* Define strlcpy if it's not available. */
63size_t strlcpy(char* dst, const char* src, size_t size);
64size_t strlcpy(char* dst, const char* src, size_t size)
65{
66        size_t result = strlen(src);
67        if (size > 0)
68        {
69                size_t copylen = size - 1;
70                if (copylen > result)
71                {
72                        copylen = result;
73                }
74                memcpy(dst, src, copylen);
75                dst[copylen] = 0;
76        }
77        return result;
78}
79#endif
80
81/*
82 * Compile time options:
83 * DARWINTRACE_SHOW_PROCESS: show the process id of every access
84 * DARWINTRACE_LOG_CREATE: log creation of files as well.
85 * DARWINTRACE_SANDBOX: control creation, deletion and writing to files and dirs.
86 * DARWINTRACE_LOG_FULL_PATH: use F_GETPATH to log the full path.
87 * DARWINTRACE_DEBUG_OUTPUT: verbose output of stuff to debug darwintrace.
88 *
89 * global variables (only checked when setup is first called)
90 * DARWINTRACE_LOG
91 *    path to the log file (no logging happens if it's unset).
92 * DARWINTRACE_SANDBOX_BOUNDS
93 *    : separated allowed paths for the creation of files.
94 *    \: -> :
95 *    \\ -> \
96 */
97
98#ifndef DARWINTRACE_SHOW_PROCESS
99#define DARWINTRACE_SHOW_PROCESS 0
100#endif
101#ifndef DARWINTRACE_LOG_CREATE
102#define DARWINTRACE_LOG_CREATE 0
103#endif
104#ifndef DARWINTRACE_SANDBOX
105#define DARWINTRACE_SANDBOX 1
106#endif
107#ifndef DARWINTRACE_DEBUG_OUTPUT
108#define DARWINTRACE_DEBUG_OUTPUT 0
109#endif
110#ifndef DARWINTRACE_LOG_FULL_PATH
111#define DARWINTRACE_LOG_FULL_PATH 1
112#endif
113
114#ifndef DEFFILEMODE
115#define DEFFILEMODE 0666
116#endif
117
118/*
119 * Prototypes.
120 */
121inline int __darwintrace_strbeginswith(const char* str, const char* prefix);
122inline void __darwintrace_log_op(const char* op, const char* procname, const char* path, int fd);
123void __darwintrace_copy_env() __attribute__((constructor));
124inline char* __darwintrace_alloc_env(const char* varName, const char* varValue);
125inline char* const* __darwintrace_restore_env(char* const envp[]);
126inline void __darwintrace_setup();
127inline void __darwintrace_cleanup_path(char *path);
128
129#define START_FD 81
130static int __darwintrace_fd = -2;
131#define BUFFER_SIZE     1024
132#if DARWINTRACE_SHOW_PROCESS
133static char __darwintrace_progname[BUFFER_SIZE];
134static pid_t __darwintrace_pid = -1;
135#endif
136#if DARWINTRACE_SANDBOX
137static char** __darwintrace_sandbox_bounds = NULL;
138#endif
139
140/* copy of the global variables */
141static char* __env_dyld_insert_libraries;
142static char* __env_dyld_force_flat_namespace;
143static char* __env_darwintrace_log;
144#if DARWINTRACE_SANDBOX
145static char* __env_darwintrace_sandbox_bounds;
146#endif
147
148#if __STDC_VERSION__==199901L
149#if DARWINTRACE_DEBUG_OUTPUT
150#define dprintf(...) fprintf(stderr, __VA_ARGS__)
151#else
152#define dprintf(...)
153#endif
154#else
155#if DARWINTRACE_DEBUG_OUTPUT
156#define dprintf(format, param) fprintf(stderr, format, param)
157#else
158#define dprintf(format, param)
159#endif
160#endif
161
162/*
163 * return 0 if str doesn't begin with prefix, 1 otherwise.
164 */
165inline int __darwintrace_strbeginswith(const char* str, const char* prefix) {
166        char theCharS;
167        char theCharP;
168        do {
169                theCharS = *str++;
170                theCharP = *prefix++;
171        } while(theCharP && (theCharP == theCharS));
172        return (theCharP == 0);
173}
174
175/*
176 * Copy the environment variables, if they're defined.
177 */
178void __darwintrace_copy_env() {
179        char* theValue;
180        theValue = getenv("DYLD_INSERT_LIBRARIES");
181        if (theValue != NULL) {
182                __env_dyld_insert_libraries = strdup(theValue);
183        } else {
184                __env_dyld_insert_libraries = NULL;
185        }
186        theValue = getenv("DYLD_FORCE_FLAT_NAMESPACE");
187        if (theValue != NULL) {
188                __env_dyld_force_flat_namespace = strdup(theValue);
189        } else {
190                __env_dyld_force_flat_namespace = NULL;
191        }
192        theValue = getenv("DARWINTRACE_LOG");
193        if (theValue != NULL) {
194                __env_darwintrace_log = strdup(theValue);
195        } else {
196                __env_darwintrace_log = NULL;
197        }
198#if DARWINTRACE_SANDBOX
199        theValue = getenv("DARWINTRACE_SANDBOX_BOUNDS");
200        if (theValue != NULL) {
201                __env_darwintrace_sandbox_bounds = strdup(theValue);
202        } else {
203                __env_darwintrace_sandbox_bounds = NULL;
204        }
205#endif
206}
207
208/*
209 * Allocate a X=Y string where X is the variable name and Y its value.
210 * Return the new string.
211 *
212 * If the value is NULL, return NULL.
213 */
214inline char* __darwintrace_alloc_env(const char* varName, const char* varValue) {
215        char* theResult = NULL;
216        if (varValue) {
217                int theSize = strlen(varName) + strlen(varValue) + 2;
218                theResult = (char*) malloc(theSize);
219                sprintf(theResult, "%s=%s", varName, varValue);
220                theResult[theSize - 1] = 0;
221        }
222       
223        return theResult;
224}
225
226/*
227 * This function checks that envp contains the global variables we had when the
228 * library was loaded and modifies it if it doesn't.
229 */
230inline char* const* __darwintrace_restore_env(char* const envp[]) {
231        /* allocate the strings. */
232        /* we don't care about the leak here because we're going to call execve,
233     * which, if it succeeds, will get rid of our heap */
234        char* dyld_insert_libraries_ptr =       
235                __darwintrace_alloc_env(
236                        "DYLD_INSERT_LIBRARIES",
237                        __env_dyld_insert_libraries);
238        char* dyld_force_flat_namespace_ptr =   
239                __darwintrace_alloc_env(
240                        "DYLD_FORCE_FLAT_NAMESPACE",
241                        __env_dyld_force_flat_namespace);
242        char* darwintrace_log_ptr =     
243                __darwintrace_alloc_env(
244                        "DARWINTRACE_LOG",
245                        __env_darwintrace_log);
246#if DARWINTRACE_SANDBOX
247        char* darwintrace_sandbox_bounds_ptr = 
248                __darwintrace_alloc_env(
249                        "DARWINTRACE_SANDBOX_BOUNDS",
250                        __env_darwintrace_sandbox_bounds);
251#endif
252
253        char* const * theEnvIter = envp;
254        int theEnvLength = 0;
255        char** theCopy;
256        char** theCopyIter;
257
258        while (*theEnvIter != NULL) {
259                theEnvLength++;
260                theEnvIter++;
261        }
262
263        /* 5 is sufficient for the four variables we copy and the terminator */
264        theCopy = (char**) malloc(sizeof(char*) * (theEnvLength + 5));
265        theEnvIter = envp;
266        theCopyIter = theCopy;
267
268        while (*theEnvIter != NULL) {
269                char* theValue = *theEnvIter;
270                if (__darwintrace_strbeginswith(theValue, "DYLD_INSERT_LIBRARIES=")) {
271                        theValue = dyld_insert_libraries_ptr;
272                        dyld_insert_libraries_ptr = NULL;
273                } else if (__darwintrace_strbeginswith(theValue, "DYLD_FORCE_FLAT_NAMESPACE=")) {
274                        theValue = dyld_force_flat_namespace_ptr;
275                        dyld_force_flat_namespace_ptr = NULL;
276                } else if (__darwintrace_strbeginswith(theValue, "DARWINTRACE_LOG=")) {
277                        theValue = darwintrace_log_ptr;
278                        darwintrace_log_ptr = NULL;
279#if DARWINTRACE_SANDBOX
280                } else if (__darwintrace_strbeginswith(theValue, "DARWINTRACE_SANDBOX_BOUNDS=")) {
281                        theValue = darwintrace_sandbox_bounds_ptr;
282                        darwintrace_sandbox_bounds_ptr = NULL;
283#endif
284                }
285               
286                if (theValue) {
287                        *theCopyIter++ = theValue;
288                }
289
290                theEnvIter++;
291        }
292       
293        if (dyld_insert_libraries_ptr) {
294                *theCopyIter++ = dyld_insert_libraries_ptr;
295        }
296        if (dyld_force_flat_namespace_ptr) {
297                *theCopyIter++ = dyld_force_flat_namespace_ptr;
298        }
299        if (darwintrace_log_ptr) {
300                *theCopyIter++ = darwintrace_log_ptr;
301        }
302#if DARWINTRACE_SANDBOX
303        if (darwintrace_sandbox_bounds_ptr) {
304                *theCopyIter++ = darwintrace_sandbox_bounds_ptr;
305        }
306#endif
307
308        *theCopyIter = 0;
309       
310        return theCopy;
311}
312
313inline void __darwintrace_setup() {
314#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
315#define close(x) syscall(SYS_close, (x))
316        if (__darwintrace_fd == -2) {
317                if (__env_darwintrace_log != NULL) {
318                        int olderrno = errno;
319                        int fd = open(__env_darwintrace_log, O_CREAT | O_WRONLY | O_APPEND, DEFFILEMODE);
320                        int newfd;
321                        for(newfd = START_FD; newfd < START_FD + 21; newfd++) {
322                                if(-1 == write(newfd, "", 0) && errno == EBADF) {
323                                        if(-1 != dup2(fd, newfd)) {
324                                                __darwintrace_fd = newfd;
325                                        }
326                                        close(fd);
327                                        fcntl(__darwintrace_fd, F_SETFD, 1); /* close-on-exec */
328                                        break;
329                                }
330                        }
331                        errno = olderrno;
332                }
333        }
334#if DARWINTRACE_SHOW_PROCESS
335        if (__darwintrace_pid == -1) {
336                char** progname = _NSGetProgname();
337                __darwintrace_pid = getpid();
338                if (progname && *progname) {
339                        strcpy(__darwintrace_progname, *progname);
340                }
341        }
342#endif
343#if DARWINTRACE_SANDBOX
344        if (__darwintrace_sandbox_bounds == NULL) {
345                if (__env_darwintrace_sandbox_bounds != NULL) {
346                        /* copy the string */
347                        char* copy = strdup(__env_darwintrace_sandbox_bounds);
348                        if (copy != NULL) {
349                                int nbPaths = 1;
350                                int nbAllocatedPaths = 5;
351                                char** paths = (char**) malloc(sizeof(char*) * nbAllocatedPaths);
352                                char* crsr = copy;
353                                char** pathsCrsr = paths;
354                                /* first path */
355                                *pathsCrsr++ = crsr;
356                                /* parse the paths (modify the copy) */
357                                do {
358                                        char theChar = *crsr;
359                                        if (theChar == '\0') {
360                                                /* the end of the paths */
361                                                break;
362                                        }
363                                        if (theChar == ':') {
364                                                /* the end of this path */
365                                                *crsr = 0;
366                                                nbPaths++;
367                                                if (nbPaths == nbAllocatedPaths) {
368                                                        nbAllocatedPaths += 5;
369                                                        paths = (char**) realloc(paths, sizeof(char*) * nbAllocatedPaths);
370                                                        /* reset the cursor in case paths pointer was moved */
371                                                        pathsCrsr = paths + (nbPaths - 1);
372                                                }
373                                                *pathsCrsr++ = crsr + 1;
374                                        }
375                                        if (theChar == '\\') {
376                                                /* escape character. test next char */
377                                                char nextChar = crsr[1];
378                                                if (nextChar == '\\') {
379                                                        /* rewrite the string */
380                                                        char* rewriteCrsr = crsr + 1;
381                                                        do {
382                                                                char theChar = *rewriteCrsr;
383                                                                rewriteCrsr[-1] = theChar;
384                                                                rewriteCrsr++;
385                                                        } while (theChar != 0);
386                                                } else if (nextChar == ':') {
387                                                        crsr++;
388                                                }
389                                                /* otherwise, ignore (keep the backslash) */
390                                        }
391                                       
392                                        /* next char */
393                                        crsr++;
394                                } while (1);
395                                /* null terminate the array */
396                                *pathsCrsr = 0;
397                                /* resize and save it */
398                                __darwintrace_sandbox_bounds = (char**) realloc(paths, sizeof(char*) * (nbPaths + 1));
399                        }
400                }
401        }
402#endif
403#undef close
404#undef open
405}
406
407/* log a call and optionally get the real path from the fd if it's not 0.
408 * op:                  the operation (open, readlink, execve)
409 * procname:    the name of the process (can be NULL)
410 * path:                the path of the file
411 * fd:                  a fd to the file, or 0 if we don't have any.
412 */
413inline void __darwintrace_log_op(const char* op, const char* procname, const char* path, int fd) {
414#if !DARWINTRACE_SHOW_PROCESS
415        #pragma unused(procname)
416#endif
417        int size;
418        char somepath[MAXPATHLEN];
419        char logbuffer[BUFFER_SIZE];
420       
421        do {
422#ifdef __APPLE__ /* Only Darwin has volfs and F_GETPATH */
423                if ((fd > 0) && (DARWINTRACE_LOG_FULL_PATH
424                        || (strncmp(path, "/.vol/", 6) == 0))) {
425                        if(fcntl(fd, F_GETPATH, somepath) == -1) {
426                                /* getpath failed. use somepath instead */
427                                strlcpy(somepath, path, sizeof(somepath));
428                                break;
429                        }
430                }
431#endif
432                if (path[0] != '/') {
433                        int len;
434                        (void) getcwd(somepath, sizeof(somepath));
435                        len = strlen(somepath);
436                        somepath[len++] = '/';
437                        strlcpy(&somepath[len], path, sizeof(somepath) - len);
438                        break;
439                }
440
441                /* otherwise, just copy the original path. */
442                strlcpy(somepath, path, sizeof(somepath));
443        } while (0);
444
445        /* clean the path. */
446        __darwintrace_cleanup_path(somepath);
447
448        size = snprintf(logbuffer, sizeof(logbuffer),
449#if DARWINTRACE_SHOW_PROCESS
450                "%s[%d]\t"
451#endif
452                "%s\t%s\n",
453#if DARWINTRACE_SHOW_PROCESS
454                procname ? procname : __darwintrace_progname, __darwintrace_pid,
455#endif
456                op, somepath );
457
458        write(__darwintrace_fd, logbuffer, size);
459        fsync(__darwintrace_fd);
460}
461
462/* remap resource fork access to the data fork.
463 * do a partial realpath(3) to fix "foo//bar" to "foo/bar"
464 */
465inline void __darwintrace_cleanup_path(char *path) {
466  size_t pathlen;
467#ifdef __APPLE__
468  size_t rsrclen;
469#endif
470  size_t i, shiftamount;
471  enum { SAWSLASH, NOTHING } state = NOTHING;
472
473  /* if this is a foo/..namedfork/rsrc, strip it off */
474  pathlen = strlen(path);
475  /* ..namedfork/rsrc is only on OS X */
476#ifdef __APPLE__
477  rsrclen = strlen(_PATH_RSRCFORKSPEC);
478  if(pathlen > rsrclen
479     && 0 == strcmp(path + pathlen - rsrclen,
480                    _PATH_RSRCFORKSPEC)) {
481    path[pathlen - rsrclen] = '\0';
482    pathlen -= rsrclen;
483  }
484#endif
485
486  /* for each position in string (including
487     terminal \0), check if we're in a run of
488     multiple slashes, and only emit the
489     first one
490  */
491  for(i=0, shiftamount=0; i <= pathlen; i++) {
492    if(state == SAWSLASH) {
493      if(path[i] == '/') {
494        /* consume it */
495        shiftamount++;
496      } else {
497        state = NOTHING;
498        path[i - shiftamount] = path[i];
499      }
500    } else {
501      if(path[i] == '/') {
502        state = SAWSLASH;
503      }
504      path[i - shiftamount] = path[i];
505    }
506  }
507
508  dprintf("darwintrace: cleanup resulted in %s\n", path);
509}
510
511#if DARWINTRACE_SANDBOX
512/*
513 * return 1 if path (once normalized) is in sandbox, 0 otherwise.
514 * return -1 if no sandbox is defined or if the path couldn't be normalized.
515 */
516inline int __darwintrace_is_in_sandbox(const char* path) {
517        int result = -1; /* no sandbox is defined */
518        __darwintrace_setup();
519        if (__darwintrace_sandbox_bounds != NULL) {
520                /* check the path */
521                char** basePathsCrsr = __darwintrace_sandbox_bounds;
522                char* basepath = *basePathsCrsr++;
523                /* normalize the path */
524                char createpath[MAXPATHLEN];
525                if (realpath(path, createpath) != NULL) {
526                        __darwintrace_cleanup_path(createpath);
527                        /* say it's outside unless it's proved inside */
528                        result = 0;
529                        while (basepath != NULL) {
530                                if (__darwintrace_strbeginswith(createpath, basepath)) {
531                                        result = 1;
532                                        break;
533                                }
534                                basepath = *basePathsCrsr++;;
535                        }
536                } /* otherwise, operation will fail anyway */
537        }
538        return result;
539}
540#endif
541
542/* Log calls to open(2) into the file specified by DARWINTRACE_LOG.
543   Only logs if the DARWINTRACE_LOG environment variable is set.
544   Only logs files (or rather, do not logs directories)
545   Only logs files where the open succeeds.
546   Only logs files opened for read access, without the O_CREAT flag set
547        (unless DARWINTRACE_LOG_CREATE is set).
548   The assumption is that any file that can be created isn't necessary
549   to build the project.
550*/
551
552int open(const char* path, int flags, ...) {
553#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
554        mode_t mode;
555        int result;
556        va_list args;
557
558        va_start(args, flags);
559        mode = va_arg(args, int);
560        va_end(args);
561#if DARWINTRACE_SANDBOX
562        result = 0;
563        if (flags & (O_CREAT | O_APPEND | O_RDWR | O_WRONLY | O_TRUNC)) {
564                int isInSandbox = __darwintrace_is_in_sandbox(path);
565                if (isInSandbox == 1) {
566                        dprintf("darwintrace: creation/writing was allowed at %s\n", path);
567                } else if (isInSandbox == 0) {
568                        /* outside sandbox, but sandbox is defined: forbid */
569                        dprintf("darwintrace: creation/writing was forbidden at %s\n", path);
570                        __darwintrace_log_op("sandbox_violation", NULL, path, 0);
571                        errno = EACCES;
572                        result = -1;
573                }
574        }
575        if (result == 0) {
576                result = open(path, flags, mode);
577        }
578#else
579        result = open(path, flags, mode);
580#endif
581        if (result >= 0) {
582                /* check that it's a file */
583                struct stat sb;
584                fstat(result, &sb);
585                if ((sb.st_mode & S_IFDIR) == 0) {
586                        if ((flags & (O_CREAT | O_WRONLY /*O_RDWR*/)) == 0 ) {
587                                __darwintrace_setup();
588                                if (__darwintrace_fd >= 0) {
589                                    dprintf("darwintrace: original open path is %s\n", path);
590                                        __darwintrace_log_op("open", NULL, path, result);
591                                }
592#if DARWINTRACE_LOG_CREATE
593                        } else if (flags & O_CREAT) {
594                                __darwintrace_setup();
595                                if (__darwintrace_fd >= 0) {
596                                    dprintf("darwintrace: original create path is %s\n", path);
597                                        __darwintrace_log_op("create", NULL, path, result);
598                                }
599#endif
600                        }
601                }
602        }
603        return result;
604#undef open
605}
606
607/* Log calls to readlink(2) into the file specified by DARWINTRACE_LOG.
608   Only logs if the DARWINTRACE_LOG environment variable is set.
609   Only logs files where the readlink succeeds.
610*/
611#ifdef READLINK_IS_NOT_P1003_1A
612int  readlink(const char * path, char * buf, int bufsiz) {
613#else
614ssize_t  readlink(const char * path, char * buf, size_t bufsiz) {
615#endif
616#define readlink(x,y,z) syscall(SYS_readlink, (x), (y), (z))
617        ssize_t result;
618
619        result = readlink(path, buf, bufsiz);
620        if (result >= 0) {
621          __darwintrace_setup();
622          if (__darwintrace_fd >= 0) {
623            dprintf("darwintrace: original readlink path is %s\n", path);
624                __darwintrace_log_op("readlink", NULL, path, 0);
625          }
626        }
627        return result;
628#undef readlink
629}
630
631int execve(const char* path, char* const argv[], char* const envp[]) {
632#define __execve(x,y,z) syscall(SYS_execve, (x), (y), (z))
633#define open(x,y,z) syscall(SYS_open, (x), (y), (z))
634#define close(x) syscall(SYS_close, (x))
635        int result;
636#if DARWINTRACE_SHOW_PROCESS
637        int saved_pid;
638#endif
639        __darwintrace_setup();
640        if (__darwintrace_fd >= 0) {
641          struct stat sb;
642          /* for symlinks, we wan't to capture
643           * both the original path and the modified one,
644           * since for /usr/bin/gcc -> gcc-4.0,
645           * both "gcc_select" and "gcc" are contributors
646           */
647          if (lstat(path, &sb) == 0) {
648                int fd;
649
650            if(S_ISLNK(sb.st_mode)) {
651              /* for symlinks, print both */
652                  __darwintrace_log_op("execve", NULL, path, 0);
653            }
654               
655                fd = open(path, O_RDONLY, 0);
656                if (fd > 0) {
657                  char buffer[MAXPATHLEN+1];
658                  ssize_t bytes_read;
659       
660                  /* once we have an open fd, if a full path was requested, do it */
661                  __darwintrace_log_op("execve", NULL, path, fd);
662
663                  /* read the file for the interpreter */
664                  bytes_read = read(fd, buffer, MAXPATHLEN);
665                  buffer[bytes_read] = 0;
666                  if (bytes_read > 2 &&
667                        buffer[0] == '#' && buffer[1] == '!') {
668                        const char* interp = &buffer[2];
669                        int i;
670                        /* skip past leading whitespace */
671                        for (i = 2; i < bytes_read; ++i) {
672                          if (buffer[i] != ' ' && buffer[i] != '\t') {
673                                interp = &buffer[i];
674                                break;
675                          }
676                        }
677                        /* found interpreter (or ran out of data)
678                           skip until next whitespace, then terminate the string */
679                        for (; i < bytes_read; ++i) {
680                          if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n') {
681                                buffer[i] = 0;
682                                break;
683                          }
684                        }
685                        /* we have liftoff */
686                        if (interp && interp[0] != '\0') {
687                          const char* procname = NULL;
688#if DARWINTRACE_SHOW_PROCESS
689                          procname = strrchr(argv[0], '/') + 1;
690                          if (procname == NULL) {
691                                procname = argv[0];
692                          }
693#endif
694                          __darwintrace_log_op("execve", procname, interp, 0);
695                        }
696                  }
697                  close(fd);
698                }
699          }
700        }
701       
702        /* call the original execve function, but fix the environment if required. */
703        result = __execve(path, argv, __darwintrace_restore_env(envp));
704        return result;
705#undef close
706#undef open
707#undef execve
708}
709
710/* if darwintrace has  been initialized, trap
711   attempts to close our file descriptor
712*/
713int close(int fd) {
714#define close(x) syscall(SYS_close, (x))
715
716  if(__darwintrace_fd != -2 && fd == __darwintrace_fd) {
717    errno = EBADF;
718    return -1;
719  }
720
721  return close(fd);
722#undef close
723}
724
725#if DARWINTRACE_SANDBOX
726/* Trap attempts to unlink a file outside the sandbox.
727 */
728int unlink(const char* path) {
729#define __unlink(x) syscall(SYS_unlink, (x))
730        int result = 0;
731        int isInSandbox = __darwintrace_is_in_sandbox(path);
732        if (isInSandbox == 1) {
733                dprintf("darwintrace: unlink was allowed at %s\n", path);
734        } else if (isInSandbox == 0) {
735                /* outside sandbox, but sandbox is defined: forbid */
736                dprintf("darwintrace: unlink was forbidden at %s\n", path);
737                __darwintrace_log_op("sandbox_violation", NULL, path, 0);
738                errno = EACCES;
739                result = -1;
740        }
741       
742        if (result == 0) {
743                result = __unlink(path);
744        }
745       
746        return result;
747}
748#endif
749
750#if DARWINTRACE_SANDBOX
751/* Trap attempts to create directories outside the sandbox.
752 */
753int mkdir(const char* path, mode_t mode) {
754#define __mkdir(x,y) syscall(SYS_mkdir, (x), (y))
755        int result = 0;
756        int isInSandbox = __darwintrace_is_in_sandbox(path);
757        if (isInSandbox == 1) {
758                dprintf("darwintrace: mkdir was allowed at %s\n", path);
759        } else if (isInSandbox == 0) {
760                /* outside sandbox, but sandbox is defined: forbid */
761                /* only consider directories that do not exist. */
762                struct stat theInfo;
763                int err;
764                err = lstat(path, &theInfo);
765                if ((err == -1) && (errno == ENOENT))
766                {
767                        dprintf("darwintrace: mkdir was forbidden at %s\n", path);
768                        __darwintrace_log_op("sandbox_violation", NULL, path, 0);
769                        errno = EACCES;
770                        result = -1;
771                } /* otherwise, mkdir will do nothing (directory exists) or fail
772                     (another error) */
773        }
774       
775        if (result == 0) {
776                result = __mkdir(path, mode);
777        }
778       
779        return result;
780}
781#endif
782
783#if DARWINTRACE_SANDBOX
784/* Trap attempts to remove directories outside the sandbox.
785 */
786int rmdir(const char* path) {
787#define __rmdir(x) syscall(SYS_rmdir, (x))
788        int result = 0;
789        int isInSandbox = __darwintrace_is_in_sandbox(path);
790        if (isInSandbox == 1) {
791                dprintf("darwintrace: rmdir was allowed at %s\n", path);
792        } else if (isInSandbox == 0) {
793                /* outside sandbox, but sandbox is defined: forbid */
794                dprintf("darwintrace: removing directory %s was forbidden\n", path);
795                __darwintrace_log_op("sandbox_violation", NULL, path, 0);
796                errno = EACCES;
797                result = -1;
798        }
799       
800        if (result == 0) {
801                result = __rmdir(path);
802        }
803       
804        return result;
805}
806#endif
807
808#if DARWINTRACE_SANDBOX
809/* Trap attempts to rename files/directories outside the sandbox.
810 */
811int rename(const char* from, const char* to) {
812#define __rename(x,y) syscall(SYS_rename, (x), (y))
813        int result = 0;
814        int isInSandbox = __darwintrace_is_in_sandbox(from);
815        if (isInSandbox == 1) {
816                dprintf("darwintrace: rename was allowed at %s\n", from);
817        } else if (isInSandbox == 0) {
818                /* outside sandbox, but sandbox is defined: forbid */
819                dprintf("darwintrace: renaming from %s was forbidden\n", from);
820                __darwintrace_log_op("sandbox_violation", NULL, from, 0);
821                errno = EACCES;
822                result = -1;
823        }
824
825        if (result == 0) {
826                isInSandbox = __darwintrace_is_in_sandbox(to);
827                if (isInSandbox == 1) {
828                        dprintf("darwintrace: rename was allowed at %s\n", to);
829                } else if (isInSandbox == 0) {
830                        /* outside sandbox, but sandbox is defined: forbid */
831                        dprintf("darwintrace: renaming to %s was forbidden\n", to);
832                        __darwintrace_log_op("sandbox_violation", NULL, to, 0);
833                        errno = EACCES;
834                        result = -1;
835                }
836        }
837       
838        if (result == 0) {
839                result = __rename(from, to);
840        }
841       
842        return result;
843}
844#endif
Note: See TracBrowser for help on using the repository browser.