/* Trap attempts to rename files/directories outside the sandbox. */ int rename(const char* from, const char* to) { #define __rename(x,y) syscall(SYS_rename, (x), (y)) int result = 0; int isInSandbox = __darwintrace_is_in_sandbox(from, 0); if (isInSandbox == 1) { debug_printf("darwintrace: rename was allowed at %s\n", from); } else if (isInSandbox == 0) { /* outside sandbox, but sandbox is defined: forbid */ debug_printf("darwintrace: renaming from %s was forbidden\n", from); errno = EACCES; result = -1; } if (result == 0) { isInSandbox = __darwintrace_is_in_sandbox(to, 0); if (isInSandbox == 1) { debug_printf("darwintrace: rename was allowed at %s\n", to); } else if (isInSandbox == 0) { /* outside sandbox, but sandbox is defined: forbid */ debug_printf("darwintrace: renaming to %s was forbidden\n", to); errno = EACCES; result = -1; } } if (result == 0) { result = __rename(from, to); } return result; }
/* Trap attempts to create directories outside the sandbox. */ int mkdir(const char* path, mode_t mode) { #define __mkdir(x,y) syscall(SYS_mkdir, (x), (y)) int result = 0; int isInSandbox = __darwintrace_is_in_sandbox(path, 0); if (isInSandbox == 1) { debug_printf("darwintrace: mkdir was allowed at %s\n", path); } else if (isInSandbox == 0) { /* outside sandbox, but sandbox is defined: forbid */ /* only consider directories that do not exist. */ struct stat theInfo; int err; err = lstat(path, &theInfo); if ((err == -1) && (errno == ENOENT)) { debug_printf("darwintrace: mkdir was forbidden at %s\n", path); errno = EACCES; result = -1; } /* otherwise, mkdir will do nothing (directory exists) or fail (another error) */ } if (result == 0) { result = __mkdir(path, mode); } return result; }
int open(const char* path, int flags, ...) { #define open(x,y,z) syscall(SYS_open, (x), (y), (z)) mode_t mode; int result; va_list args; struct stat sb; char newpath[MAXPATHLEN]; int isInSandbox; /* Why mode here ? */ va_start(args, flags); mode = va_arg(args, int); va_end(args); result = 0; if((stat(path, &sb)!=-1 && !(sb.st_mode&S_IFDIR)) || flags & O_CREAT ) { *newpath=0; __darwintrace_setup(); isInSandbox = __darwintrace_is_in_sandbox(path, newpath); if (isInSandbox == 0) { debug_printf("darwintrace: creation/writing was forbidden at %s\n", path); errno = EACCES; result = -1; } if(*newpath) path=newpath; } if (result == 0) { result = open(path, flags, mode); } return result; #undef open }
/** * Wrapper around \c rmdir(2) to deny deleting directories outside of the * sandbox. */ static int _dt_rmdir(const char *path) { #define rmdir(x) syscall(SYS_rmdir, (x)) __darwintrace_setup(); int result = 0; if (!__darwintrace_is_in_sandbox(path, DT_REPORT | DT_FOLLOWSYMS)) { errno = ENOENT; result = -1; } else { result = rmdir(path); } debug_printf("rmdir(%s) = %d\n", path, result); return result; #undef rmdir }
static int _dt_access(const char *path, int amode) { #define access(x, y) syscall(SYS_access, (x), (y)) __darwintrace_setup(); int result = 0; if (!__darwintrace_is_in_sandbox(path, DT_REPORT | DT_ALLOWDIR | DT_FOLLOWSYMS)) { errno = ENOENT; result = -1; } else { result = access(path, amode); } debug_printf("access(%s) = %d\n", path, result); return result; #undef access }
/* Trap attempts to remove directories outside the sandbox. */ int rmdir(const char* path) { #define __rmdir(x) syscall(SYS_rmdir, (x)) int result = 0; int isInSandbox = __darwintrace_is_in_sandbox(path, 0); if (isInSandbox == 1) { debug_printf("darwintrace: rmdir was allowed at %s\n", path); } else if (isInSandbox == 0) { /* outside sandbox, but sandbox is defined: forbid */ debug_printf("darwintrace: removing directory %s was forbidden\n", path); errno = EACCES; result = -1; } if (result == 0) { result = __rmdir(path); } return result; }
/* Trap attempts to unlink a file outside the sandbox. */ int unlink(const char* path) { #define __unlink(x) syscall(SYS_unlink, (x)) int result = 0; int isInSandbox = __darwintrace_is_in_sandbox(path, 0); if (isInSandbox == 1) { debug_printf("darwintrace: unlink was allowed at %s\n", path); } else if (isInSandbox == 0) { /* outside sandbox, but sandbox is defined: forbid */ debug_printf("darwintrace: unlink was forbidden at %s\n", path); errno = EACCES; result = -1; } if (result == 0) { result = __unlink(path); } return result; }
int readlink(const char * path, char * buf, int bufsiz) { #else ssize_t readlink(const char * path, char * buf, size_t bufsiz) { #endif #define readlink(x,y,z) syscall(SYS_readlink, (x), (y), (z)) ssize_t result; int isInSandbox; result = readlink(path, buf, bufsiz); if (result >= 0) { __darwintrace_setup(); isInSandbox = __darwintrace_is_in_sandbox(path, 0); if (!isInSandbox) { errno=EACCES; result=-1; } } return result; #undef readlink }
int lstat64(const char * path, struct stat64 * sb) { #define lstat64(path, sb) syscall(SYS_lstat64, path, sb) int result=0; char newpath[260]; *newpath=0; if(!is_directory(path)&&__darwintrace_is_in_sandbox(path, newpath)==0) { errno=ENOENT; result=-1; }else { if(*newpath) path=newpath; result=lstat64(path, sb); } return result; #undef lstat64 }
static int _dt_readlink(const char *path, char *buf, int bufsiz) { #else static ssize_t _dt_readlink(const char *path, char *buf, size_t bufsiz) { #endif #define readlink(x,y,z) syscall(SYS_readlink, (x), (y), (z)) __darwintrace_setup(); int result = 0; // don't follow symlinks here; whether access to the link target is allowed // or not does not matter for reading the symlink if (!__darwintrace_is_in_sandbox(path, DT_REPORT | DT_ALLOWDIR)) { errno = ENOENT; result = -1; } else { result = readlink(path, buf, bufsiz); } debug_printf("readlink(%s) = %d\n", path, result); return result; #undef readlink }
int execve(const char* path, char* const argv[], char* const envp[]) { #define __execve(x,y,z) syscall(SYS_execve, (x), (y), (z)) #define open(x,y,z) syscall(SYS_open, (x), (y), (z)) #define close(x) syscall(SYS_close, (x)) #define lstat(x, y) syscall(SYS_lstat, (x), (y)) int result; __darwintrace_setup(); if (__darwintrace_fd >= 0) { struct stat sb; /* for symlinks, we want to capture * both the original path and the modified one, * since for /usr/bin/gcc -> gcc-4.0, * both "gcc_select" and "gcc" are contributors */ if (lstat(path, &sb) == 0) { int fd; if(S_ISLNK(sb.st_mode)) { /* for symlinks, print both */ __darwintrace_log_op("execve", path, 0); } fd = open(path, O_RDONLY, 0); if (fd > 0) { char buffer[MAXPATHLEN+1], newpath[MAXPATHLEN+1]; ssize_t bytes_read; *newpath=0; if(__darwintrace_is_in_sandbox(path, newpath)==0) { close(fd); errno=ENOENT; return -1; } if(*newpath) path=newpath; /* once we have an open fd, if a full path was requested, do it */ __darwintrace_log_op("execve", path, fd); /* read the file for the interpreter */ bytes_read = read(fd, buffer, MAXPATHLEN); buffer[bytes_read] = 0; if (bytes_read > 2 && buffer[0] == '#' && buffer[1] == '!') { const char* interp = &buffer[2]; int i; /* skip past leading whitespace */ for (i = 2; i < bytes_read; ++i) { if (buffer[i] != ' ' && buffer[i] != '\t') { interp = &buffer[i]; break; } } /* found interpreter (or ran out of data) skip until next whitespace, then terminate the string */ for (; i < bytes_read; ++i) { if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n') { buffer[i] = 0; break; } } /* we have liftoff */ if (interp && interp[0] != '\0') { __darwintrace_log_op("execve", interp, 0); } } close(fd); } } close(__darwintrace_fd); __darwintrace_fd=-1; } /* call the original execve function, but fix the environment if required. */ result = __execve(path, argv, __darwintrace_restore_env(envp)); return result; #undef lstat #undef close #undef open #undef execve }