/* * Path sandbox for the gentoo linux portage package system, initially * based on the ROCK Linux Wrapper for getting a list of created files * * to integrate with bash, bash should have been built like this * * ./configure --prefix= --host= --without-gnu-malloc * * it's very important that the --enable-static-link option is NOT specified * * Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com * Distributed under the terms of the GNU General Public License, v2 or later * Author : Geert Bevin * * Post Bevin leaving Gentoo ranks: * -------------------------------- * Ripped out all the wrappers, and implemented those of InstallWatch. * Losts of cleanups and bugfixes. Implement a execve that forces $LIBSANDBOX * in $LD_PRELOAD. Reformat the whole thing to look somewhat like the reworked * sandbox.c from Brad House . * * Martin Schlemmer (18 Aug 2002) * * Partly Copyright (C) 1998-9 Pancrazio `Ezio' de Mauro , * as some of the InstallWatch code was used. * * * $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-dev/Attic/libsandbox.c,v 1.4 2002/12/16 22:28:05 jrray Exp $ * */ /* Uncomment below to enable wrapping of mknod(). * This is broken currently. */ /* #define WRAP_MKNOD */ #define open xxx_open #define open64 xxx_open64 /* Wrapping mknod, do not have any effect, and * wrapping __xmknod causes calls to it to segfault */ #ifdef WRAP_MKNOD # define __xmknod xxx___xmknod #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef WRAP_MKNOD # undef __xmknod #endif #undef open #undef open64 #include "localdecls.h" #include "sandbox.h" #define PIDS_FILE "/tmp/sandboxpids.tmp" #define FUNCTION_SANDBOX_SAFE(func, path) \ ((0 == is_sandbox_on()) || (1 == before_syscall(func, path))) #define FUNCTION_SANDBOX_SAFE_INT(func, path, flags) \ ((0 == is_sandbox_on()) || (1 == before_syscall_open_int(func, path, flags))) #define FUNCTION_SANDBOX_SAFE_CHAR(func, path, mode) \ ((0 == is_sandbox_on()) || (1 == before_syscall_open_char(func, path, mode))) /* Macro to check if a wrapper is defined, if not * then try to resolve it again. */ #define check_dlsym(name) \ { \ int old_errno=errno; \ if (!true_ ## name) true_ ## name=get_dlsym(#name); \ errno=old_errno; \ } static char sandbox_lib[255]; typedef struct { char *last_env; int count; char **strs; } sbprefix_t; typedef struct { int show_access_violation; sbprefix_t deny; sbprefix_t read; sbprefix_t write; sbprefix_t predict; } sbcontext_t; /* glibc modified realpath() functions */ char *erealpath (const char *name, char *resolved); static void init_wrappers(void); static void *get_dlsym(const char *); static void canonicalize(const char *, char *); static int check_access(sbcontext_t *, const char *, const char *); static int check_syscall(sbcontext_t *, const char *, const char *); static int before_syscall(const char *, const char *); static int before_syscall_open_int(const char *, const char *, int); static int before_syscall_open_char(const char *, const char *, const char *); static void clean_env_entries(sbprefix_t *); static void init_context(sbcontext_t *); static void init_env_entries(sbprefix_t *, char *); static char* filter_path(const char*); static int is_sandbox_on(); static int is_sandbox_pid(); /* Wrapped functions */ extern int chmod(const char *, mode_t); static int(*true_chmod)(const char *, mode_t); extern int chown(const char *, uid_t, gid_t); static int(*true_chown)(const char *, uid_t, gid_t); extern int creat(const char *, mode_t); static int(*true_creat)(const char *, mode_t); extern FILE *fopen(const char *,const char*); static FILE *(*true_fopen)(const char *,const char*); extern int lchown(const char *, uid_t, gid_t); static int(*true_lchown)(const char *, uid_t, gid_t); extern int link(const char *, const char *); static int(*true_link)(const char *, const char *); extern int mkdir(const char *, mode_t); static int(*true_mkdir)(const char *, mode_t); extern DIR *opendir(const char *); static DIR *(*true_opendir)(const char *); #ifdef WRAP_MKNOD extern int __xmknod(const char *, mode_t, dev_t); static int(*true___xmknod)(const char *, mode_t, dev_t); #endif extern int open(const char *, int, ...); static int(*true_open)(const char *, int, ...); extern int rename(const char *, const char *); static int(*true_rename)(const char *, const char *); extern int rmdir(const char *); static int(*true_rmdir)(const char *); extern int symlink(const char *, const char *); static int(*true_symlink)(const char *, const char *); extern int truncate(const char *, TRUNCATE_T); static int(*true_truncate)(const char *, TRUNCATE_T); extern int unlink(const char *); static int(*true_unlink)(const char *); #if (GLIBC_MINOR >= 1) extern int creat64(const char *, __mode_t); static int(*true_creat64)(const char *, __mode_t); extern FILE *fopen64(const char *,const char *); static FILE *(*true_fopen64)(const char *,const char *); extern int open64(const char *, int, ...); static int(*true_open64)(const char *, int, ...); extern int truncate64(const char *, __off64_t); static int(*true_truncate64)(const char *, __off64_t); #endif extern int execve(const char *filename, char *const argv [], char *const envp[]); static int (*true_execve)(const char *, char *const [], char *const []); static sbcontext_t* sbcontext = NULL; static sem_t ctxsem; /* * Initialize the shabang */ static void init_wrappers(void) { void *libc_handle = NULL; #ifdef BROKEN_RTLD_NEXT // printf ("RTLD_LAZY"); libc_handle = dlopen(LIBC_VERSION, RTLD_LAZY); #else // printf ("RTLD_NEXT"); libc_handle = RTLD_NEXT; #endif true_chmod = dlsym(libc_handle, "chmod"); true_chown = dlsym(libc_handle, "chown"); true_creat = dlsym(libc_handle, "creat"); true_fopen = dlsym(libc_handle, "fopen"); true_lchown = dlsym(libc_handle, "lchown"); true_link = dlsym(libc_handle, "link"); true_mkdir = dlsym(libc_handle, "mkdir"); true_opendir = dlsym(libc_handle, "opendir"); #ifdef WRAP_MKNOD true___xmknod = dlsym(libc_handle, "__xmknod"); #endif true_open = dlsym(libc_handle, "open"); true_rename = dlsym(libc_handle, "rename"); true_rmdir = dlsym(libc_handle, "rmdir"); true_symlink = dlsym(libc_handle, "symlink"); true_truncate = dlsym(libc_handle, "truncate"); true_unlink = dlsym(libc_handle, "unlink"); #if (GLIBC_MINOR >= 1) true_creat64 = dlsym(libc_handle, "creat64"); true_fopen64 = dlsym(libc_handle, "fopen64"); true_open64 = dlsym(libc_handle, "open64"); true_truncate64 = dlsym(libc_handle, "truncate64"); #endif true_execve = dlsym(libc_handle, "execve"); } void _init(void) { int old_errno = errno; char *tmp_string = NULL; if (sem_init(&ctxsem, 0, 1)) { fprintf(stderr, "Failed to create semaphore\n"); abort(); } init_wrappers(); /* Get the path and name to this library */ tmp_string = get_sandbox_lib("/"); strncpy(sandbox_lib, tmp_string, 254); if (tmp_string) free(tmp_string); tmp_string = NULL; errno = old_errno; } void _fini(void) { if (sbcontext) { clean_env_entries(&sbcontext->deny); clean_env_entries(&sbcontext->read); clean_env_entries(&sbcontext->write); clean_env_entries(&sbcontext->predict); free(sbcontext); sbcontext = NULL; } /* free the semaphore */ sem_destroy(&ctxsem); } static void canonicalize(const char *path, char *resolved_path) { int old_errno = errno; /* If path == NULL, return or we get a segfault */ if (NULL == path) return; if(!erealpath(path, resolved_path) && (path[0] != '/')) { /* The path could not be canonicalized, append it * to the current working directory if it was not * an absolute path */ getcwd(resolved_path, MAXPATHLEN - 2); strcat(resolved_path, "/"); strncat(resolved_path, path, MAXPATHLEN - 1 - strlen(resolved_path)); erealpath(resolved_path, resolved_path); } errno = old_errno; } static void *get_dlsym(const char *symname) { void *libc_handle = NULL; void *symaddr = NULL; #ifdef BROKEN_RTLD_NEXT libc_handle = dlopen(LIBC_VERSION, RTLD_LAZY); if (!libc_handle) { printf("libsandbox.so: Can't dlopen libc: %s\n", dlerror()); abort(); } #else libc_handle = RTLD_NEXT; #endif symaddr = dlsym(libc_handle, symname); if (!symaddr) { printf("libsandbox.so: Can't resolve %s: %s\n", symname, dlerror()); abort(); } return symaddr; } /* * Wrapper Functions */ int chmod(const char *path, mode_t mode) { int result = -1; char canonic[MAXPATHLEN]; canonicalize(path, canonic); if FUNCTION_SANDBOX_SAFE("chmod", canonic) { check_dlsym(chmod); result = true_chmod(path, mode); } return result; } int chown(const char *path, uid_t owner, gid_t group) { int result = -1; char canonic[MAXPATHLEN]; canonicalize(path, canonic); if FUNCTION_SANDBOX_SAFE("chown", canonic) { check_dlsym(chown); result = true_chown(path, owner, group); } return result; } int creat(const char *pathname, mode_t mode) { /* Is it a system call? */ int result = -1; char canonic[MAXPATHLEN]; canonicalize(pathname, canonic); if FUNCTION_SANDBOX_SAFE("creat", canonic) { check_dlsym(open); result = true_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); } return result; } FILE *fopen(const char *pathname, const char *mode) { FILE *result = NULL; char canonic[MAXPATHLEN]; canonicalize(pathname, canonic); if FUNCTION_SANDBOX_SAFE_CHAR("fopen", canonic, mode) { check_dlsym(fopen); result = true_fopen(pathname,mode); } return result; } int lchown(const char *path, uid_t owner, gid_t group) { /* Linux specific? */ int result = -1; char canonic[MAXPATHLEN]; canonicalize(path, canonic); if FUNCTION_SANDBOX_SAFE("lchown", canonic) { check_dlsym(chown); result = true_chown(path, owner, group); } return result; } int link(const char *oldpath, const char *newpath) { int result = -1; char old_canonic[MAXPATHLEN], new_canonic[MAXPATHLEN]; canonicalize(oldpath, old_canonic); canonicalize(newpath, new_canonic); if FUNCTION_SANDBOX_SAFE("link", new_canonic) { check_dlsym(link); result = true_link(oldpath, newpath); } return result; } int mkdir(const char *pathname, mode_t mode) { int result = -1; char canonic[MAXPATHLEN]; canonicalize(pathname, canonic); if FUNCTION_SANDBOX_SAFE("mkdir", canonic) { check_dlsym(mkdir); result = true_mkdir(pathname, mode); } return result; } DIR *opendir(const char *name) { DIR *result = NULL; char canonic[MAXPATHLEN]; canonicalize(name, canonic); if FUNCTION_SANDBOX_SAFE("opendir", canonic) { check_dlsym(opendir); result = true_opendir(name); } return result; } #ifdef WRAP_MKNOD int __xmknod(const char *pathname, mode_t mode, dev_t dev) { int result = -1; char canonic[MAXPATHLEN]; canonicalize(pathname, canonic); if FUNCTION_SANDBOX_SAFE("__xmknod", canonic) { check_dlsym(__xmknod); result = true___xmknod(pathname, mode, dev); } return result; } #endif int open(const char *pathname, int flags, ...) { /* Eventually, there is a third parameter: it's mode_t mode */ va_list ap; mode_t mode = 0; int result = -1; char canonic[MAXPATHLEN]; if (flags & O_CREAT) { va_start(ap, flags); mode = va_arg(ap, mode_t); va_end(ap); } canonicalize(pathname, canonic); if FUNCTION_SANDBOX_SAFE_INT("open", canonic, flags) { /* We need to resolve open() realtime in some cases, * else we get a segfault when running /bin/ps, etc * in a sandbox */ check_dlsym(open); result=true_open(pathname, flags, mode); } return result; } int rename(const char *oldpath, const char *newpath) { int result = -1; char old_canonic[MAXPATHLEN], new_canonic[MAXPATHLEN]; canonicalize(oldpath, old_canonic); canonicalize(newpath, new_canonic); if FUNCTION_SANDBOX_SAFE("rename", new_canonic) { check_dlsym(rename); result = true_rename(oldpath, newpath); } return result; } int rmdir(const char *pathname) { int result = -1; char canonic[MAXPATHLEN]; canonicalize(pathname, canonic); if FUNCTION_SANDBOX_SAFE("rmdir", canonic) { check_dlsym(rmdir); result = true_rmdir(pathname); } return result; } int symlink(const char *oldpath, const char *newpath) { int result = -1; char old_canonic[MAXPATHLEN], new_canonic[MAXPATHLEN]; canonicalize(oldpath, old_canonic); canonicalize(newpath, new_canonic); if FUNCTION_SANDBOX_SAFE("symlink", new_canonic) { check_dlsym(symlink); result = true_symlink(oldpath, newpath); } return result; } int truncate(const char *path, TRUNCATE_T length) { int result = -1; char canonic[MAXPATHLEN]; canonicalize(path, canonic); if FUNCTION_SANDBOX_SAFE("truncate", canonic) { check_dlsym(truncate); result = true_truncate(path, length); } return result; } int unlink(const char *pathname) { int result = -1; char canonic[MAXPATHLEN]; canonicalize(pathname, canonic); if FUNCTION_SANDBOX_SAFE("unlink", canonic) { check_dlsym(unlink); result = true_unlink(pathname); } return result; } #if (GLIBC_MINOR >= 1) int creat64(const char *pathname, __mode_t mode) { /* Is it a system call? */ int result = -1; char canonic[MAXPATHLEN]; canonicalize(pathname, canonic); if FUNCTION_SANDBOX_SAFE("creat64", canonic) { check_dlsym(open64); result = true_open64(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); } return result; } FILE *fopen64(const char *pathname, const char *mode) { FILE *result = NULL; char canonic[MAXPATHLEN]; canonicalize(pathname, canonic); if FUNCTION_SANDBOX_SAFE_CHAR("fopen64", canonic, mode) { check_dlsym(fopen64); result = true_fopen(pathname,mode); } return result; } int open64(const char *pathname, int flags, ...) { /* Eventually, there is a third parameter: it's mode_t mode */ va_list ap; mode_t mode = 0; int result = -1; char canonic[MAXPATHLEN]; if (flags & O_CREAT) { va_start(ap, flags); mode = va_arg(ap, mode_t); va_end(ap); } canonicalize(pathname, canonic); if FUNCTION_SANDBOX_SAFE_INT("open64", canonic, flags) { check_dlsym(open64); result=true_open64(pathname, flags, mode); } return result; } int truncate64(const char *path, __off64_t length) { int result = -1; char canonic[MAXPATHLEN]; canonicalize(path, canonic); if FUNCTION_SANDBOX_SAFE("truncate64", canonic) { check_dlsym(truncate64); result = true_truncate64(path, length); } return result; } #endif /* GLIBC_MINOR >= 1 */ /* * Exec Wrappers */ int execve(const char *filename, char *const argv [], char *const envp[]) { int old_errno = errno; int result = -1; int count = 0; char canonic[MAXPATHLEN]; char *old_envp = NULL; char *new_envp = NULL; canonicalize(filename, canonic); if FUNCTION_SANDBOX_SAFE("execve", canonic) { while (envp[count] != NULL) { if (strstr(envp[count], "LD_PRELOAD=") == envp[count]) { if (NULL != strstr(envp[count], sandbox_lib)) { break; } else { const int max_envp_len = strlen(envp[count]) + strlen(sandbox_lib) + 1; /* Backup envp[count], and set it to our own one which * contains sandbox_lib */ old_envp = envp[count]; new_envp = strndupa(old_envp, max_envp_len - 1); /* LD_PRELOAD already have variables other than sandbox_lib, * thus we have to add sandbox_lib via a white space. */ if (0 != strcmp(envp[count], "LD_PRELOAD=")) { strncpy(new_envp + strlen(old_envp), ":", max_envp_len - strlen(new_envp)); strncpy(new_envp + strlen(old_envp) + 1, sandbox_lib, max_envp_len - strlen(new_envp)); } else { strncpy(new_envp + strlen(old_envp), sandbox_lib, max_envp_len - strlen(new_envp)); } /* Valid string? */ new_envp[max_envp_len] = '\0'; /* envp[count] = new_envp; * * Get rid of the "read-only" warnings */ memcpy((void *)&envp[count], &new_envp, sizeof(new_envp)); break; } } count++; } errno = old_errno; check_dlsym(execve); result = true_execve(filename, argv, envp); old_errno = errno; if (old_envp) { /* Restore envp[count] again. * * envp[count] = old_envp; */ memcpy((void *)&envp[count], &old_envp, sizeof(old_envp)); old_envp = NULL; } } errno = old_errno; return result; } /* * Internal Functions */ #if (GLIBC_MINOR == 1) /* This hack is needed for glibc 2.1.1 (and others?) * (not really needed, but good example) */ extern int fclose(FILE *); static int (*true_fclose)(FILE *) = NULL; int fclose(FILE *file) { int result = - 1; check_dlsym(fclose); result = true_fclose(file); return result; } #endif /* GLIBC_MINOR == 1 */ static void init_context(sbcontext_t* context) { memset(context, 0, sizeof(sbcontext_t)); context->show_access_violation = 1; } static int is_sandbox_pid() { int old_errno = errno; int result = 0; FILE* pids_stream = NULL; int pids_file = -1; int current_pid = 0; int tmp_pid = 0; init_wrappers(); pids_stream = true_fopen(PIDS_FILE, "r"); if (NULL == pids_stream) { perror(">>> pids file fopen"); } else { pids_file = fileno(pids_stream); if (pids_file < 0) { perror(">>> pids file fileno"); } else { current_pid = getpid(); while (EOF != fscanf(pids_stream, "%d\n", &tmp_pid)) { if (tmp_pid == current_pid) { result = 1; break; } } } if (EOF == fclose(pids_stream)) { perror(">>> pids file fclose"); } pids_stream = NULL; pids_file = -1; } errno = old_errno; return result; } static void clean_env_entries(sbprefix_t* prefix) { int old_errno = errno; int i = 0; if (NULL != prefix->strs) { for (i = 0; i < prefix->count; i++) { if (NULL != prefix->strs[i]) { free(prefix->strs[i]); prefix->strs[i] = NULL; } } free(prefix->strs); prefix->strs = NULL; prefix->count = 0; } if (prefix->last_env) { free(prefix->last_env); prefix->last_env = NULL; } errno = old_errno; } static void init_env_entries(sbprefix_t* prefix, char* env) { int old_errno = errno; char* prefixes_env = getenv(env); if (NULL == prefixes_env) { fprintf(stderr, "Sandbox error : the %s environmental variable should be defined.\n", env); } else { char *ptr; int num_colons = 0; /* Check to see if the env value has changed since the last time this was initalized, don't do the work again if it hasn't. */ if (prefix->last_env && !strcmp(prefix->last_env, prefixes_env)) { errno = old_errno; return; } /* Clean any existing entries */ clean_env_entries(prefix); /* Env value is different, update the cached copy */ prefix->last_env = strdup(prefixes_env); ptr = prefixes_env; while (*ptr) { if (*ptr++ == ':') ++num_colons; } if (prefix->strs) { free(prefix->strs); prefix->strs = 0; } prefix->strs = (char**)malloc((num_colons+1) * sizeof(char*)); if (!prefix->strs) return; memset(prefix->strs, 0, (num_colons+1) * sizeof(char*)); prefix->count = 0; ptr = prefixes_env; while (*ptr) { char *next_colon = strchr(ptr, ':'); if (next_colon) { if (next_colon != ptr) { char *str = strndup(ptr, next_colon-ptr); if (!str) return; prefix->strs[prefix->count++] = filter_path(str); free(str); } } else { prefix->strs[prefix->count++] = filter_path(ptr); break; } ptr = next_colon+1; } } errno = old_errno; } static char* filter_path(const char* path) { int old_errno = errno; char* filtered_path = (char *)malloc(MAXPATHLEN * sizeof(char)); filtered_path[0] = 0; canonicalize(path, filtered_path); errno = old_errno; return filtered_path; } static int check_access(sbcontext_t* sbcontext, const char* func, const char* path) { int old_errno = errno; int result = -1; int i = 0; char* filtered_path = filter_path(path); if (!filtered_path) { errno = old_errno; return 0; } if ('/' != filtered_path[0]) { free(filtered_path); errno = old_errno; return 0; } if ((0 == strncmp(filtered_path, "/etc/ld.so.preload", 18)) && (is_sandbox_pid())) { result = 1; } if (-1 == result) { if (NULL != sbcontext->deny.strs) { for (i = 0; i < sbcontext->deny.count; i++) { if (NULL != sbcontext->deny.strs[i]) { if (0 == strncmp(filtered_path, sbcontext->deny.strs[i], strlen(sbcontext->deny.strs[i]))) { result = 0; break; } } } } if (-1 == result) { if ((NULL != sbcontext->read.strs) && ((0 == strncmp(func, "open_rd", 7)) || (0 == strncmp(func, "popen", 5)) || (0 == strncmp(func, "opendir", 7)) || (0 == strncmp(func, "system", 6)) || (0 == strncmp(func, "execl", 5)) || (0 == strncmp(func, "execlp", 6)) || (0 == strncmp(func, "execle", 6)) || (0 == strncmp(func, "execv", 5)) || (0 == strncmp(func, "execvp", 6)) || (0 == strncmp(func, "execve", 6)) ) ) { for (i = 0; i < sbcontext->read.count; i++) { if (NULL != sbcontext->read.strs[i]) { if (0 == strncmp(filtered_path, sbcontext->read.strs[i], strlen(sbcontext->read.strs[i]))) { result = 1; break; } } } } else if ((NULL != sbcontext->write.strs) && ((0 == strncmp(func, "open_wr", 7)) || (0 == strncmp(func, "creat", 5)) || (0 == strncmp(func, "creat64", 7)) || (0 == strncmp(func, "mkdir", 5)) || (0 == strncmp(func, "mknod", 5)) || (0 == strncmp(func, "mkfifo", 6)) || (0 == strncmp(func, "link", 4)) || (0 == strncmp(func, "symlink", 7)) || (0 == strncmp(func, "rename", 6)) || (0 == strncmp(func, "utime", 5)) || (0 == strncmp(func, "utimes", 6)) || (0 == strncmp(func, "unlink", 6)) || (0 == strncmp(func, "rmdir", 5)) || (0 == strncmp(func, "chown", 5)) || (0 == strncmp(func, "lchown", 6)) || (0 == strncmp(func, "chmod", 5)) || (0 == strncmp(func, "truncate", 8)) || (0 == strncmp(func, "ftruncate", 9)) || (0 == strncmp(func, "truncate64", 10)) || (0 == strncmp(func, "ftruncate64", 11)) ) ) { struct stat tmp_stat; #if 0 // write_denied is never set for (i = 0; i < sbcontext->write_denied.count; i++) { if (NULL != sbcontext->write_denied.strs[i]) { if (0 == strncmp(filtered_path, sbcontext->write_denied.strs[i], strlen(sbcontext->write_denied.strs[i]))) { result = 0; break; } } } #endif if (-1 == result) { for (i = 0; i < sbcontext->write.count; i++) { if (NULL != sbcontext->write.strs[i]) { if (0 == strncmp(filtered_path, sbcontext->write.strs[i], strlen(sbcontext->write.strs[i]))) { result = 1; break; } } } if (-1 == result) { /* hack to prevent mkdir of existing dirs to show errors */ if (0 == strncmp(func, "mkdir", 5)) { if (0 == stat(filtered_path, &tmp_stat)) { sbcontext->show_access_violation = 0; result = 0; } } if (-1 == result) { for (i = 0; i < sbcontext->predict.count; i++) { if (NULL != sbcontext->predict.strs[i]) { if (0 == strncmp(filtered_path, sbcontext->predict.strs[i], strlen(sbcontext->predict.strs[i]))) { sbcontext->show_access_violation = 0; result = 0; break; } } } } } } } } } if (-1 == result) { result = 0; } if (filtered_path) free(filtered_path); filtered_path = NULL; errno = old_errno; return result; } static int check_syscall(sbcontext_t* sbcontext, const char* func, const char* file) { int old_errno = errno; int result = 1; struct stat log_stat; char* log_path = NULL; char* absolute_path = NULL; char* tmp_buffer = NULL; int log_file = 0; struct stat debug_log_stat; char* debug_log_env = NULL; char* debug_log_path = NULL; int debug_log_file = 0; char buffer[512]; init_wrappers(); if ('/' == file[0]) { absolute_path = (char *)malloc((strlen(file) + 1) * sizeof(char)); sprintf(absolute_path, "%s", file); } else { tmp_buffer = get_current_dir_name(); absolute_path = (char *)malloc((strlen(tmp_buffer) + 1 + strlen(file) + 1) * sizeof(char)); sprintf(absolute_path,"%s/%s", tmp_buffer, file); if (tmp_buffer) free(tmp_buffer); tmp_buffer = NULL; } log_path = getenv("SANDBOX_LOG"); debug_log_env = getenv("SANDBOX_DEBUG"); debug_log_path = getenv("SANDBOX_DEBUG_LOG"); if (((NULL == log_path) || (0 != strncmp(absolute_path, log_path, strlen(log_path)))) && ((NULL == debug_log_env) || (NULL == debug_log_path) || (0 != strncmp(absolute_path, debug_log_path, strlen(debug_log_path)))) && (0 == check_access(sbcontext, func, absolute_path)) ) { if (1 == sbcontext->show_access_violation) { fprintf(stderr, "\e[31;01mACCESS DENIED\033[0m %s:%*s%s\n", func, (int)(10 - strlen(func)), "", absolute_path); if (NULL != log_path) { sprintf(buffer, "%s:%*s%s\n", func, (int)(10 - strlen(func)), "", absolute_path); if ((0 == lstat(log_path, &log_stat)) && (0 == S_ISREG(log_stat.st_mode)) ) { fprintf(stderr, "\e[31;01mSECURITY BREACH\033[0m %s already exists and is not a regular file.\n", log_path); } else { log_file = true_open(log_path, O_APPEND | O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if(log_file >= 0) { write(log_file, buffer, strlen(buffer)); close(log_file); } } } } result = 0; } else if (NULL != debug_log_env) { if (NULL != debug_log_path) { if (0 != strncmp(absolute_path, debug_log_path, strlen(debug_log_path))) { sprintf(buffer, "%s:%*s%s\n", func, (int)(10 - strlen(func)), "", absolute_path); if ((0 == lstat(debug_log_path, &debug_log_stat)) && (0 == S_ISREG(debug_log_stat.st_mode)) ) { fprintf(stderr, "\e[31;01mSECURITY BREACH\033[0m %s already exists and is not a regular file.\n", log_path); } else { debug_log_file = true_open(debug_log_path, O_APPEND | O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if(debug_log_file >= 0) { write(debug_log_file, buffer, strlen(buffer)); close(debug_log_file); } } } } else { fprintf(stderr, "\e[32;01mACCESS ALLOWED\033[0m %s:%*s%s\n", func, (int)(10 - strlen(func)), "", absolute_path); } } if (absolute_path) free(absolute_path); absolute_path = NULL; errno = old_errno; return result; } static int is_sandbox_on() { int old_errno = errno; /* $SANDBOX_ACTIVE is an env variable that should ONLY * be used internal by sandbox.c and libsanbox.c. External * sources should NEVER set it, else the sandbox is enabled * in some cases when run in parallel with another sandbox, * but not even in the sandbox shell. * * Azarah (3 Aug 2002) */ if ((NULL != getenv("SANDBOX_ON")) && (0 == strncmp(getenv("SANDBOX_ON"), "1", 1)) && (NULL != getenv("SANDBOX_ACTIVE")) && (0 == strncmp(getenv("SANDBOX_ACTIVE"), "armedandready", 13)) ) { errno = old_errno; return 1; } else { errno = old_errno; return 0; } } static int before_syscall(const char* func, const char* file) { int old_errno = errno; int result = 1; /* Only allow one thread to access sbcontext at a time */ sem_wait(&ctxsem); if (!sbcontext) { sbcontext = (sbcontext_t*)malloc(sizeof(sbcontext_t)); init_context(sbcontext); } else { /* sometimes this value gets set to 0 */ sbcontext->show_access_violation = 1; } init_env_entries(&sbcontext->deny, "SANDBOX_DENY"); init_env_entries(&sbcontext->read, "SANDBOX_READ"); init_env_entries(&sbcontext->write, "SANDBOX_WRITE"); init_env_entries(&sbcontext->predict, "SANDBOX_PREDICT"); result = check_syscall(sbcontext, func, file); if (sem_post(&ctxsem)) { fprintf(stderr, "Failed trying to release semaphore\n"); } errno = old_errno; if (0 == result) { errno = EACCES; } return result; } static int before_syscall_open_int(const char* func, const char* file, int flags) { if ((flags & O_WRONLY) || (flags & O_RDWR)) { return before_syscall("open_wr", file); } else { return before_syscall("open_rd", file); } } static int before_syscall_open_char(const char* func, const char* file, const char* mode) { if ((strcmp(mode, "r") == 0) || (strcmp(mode, "rb") == 0)) { return before_syscall("open_rd", file); } else { return before_syscall("open_wr", file); } } // vim:expandtab noai:cindent ai