summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/sandbox-dev/libsandbox.c')
-rw-r--r--src/sandbox-dev/libsandbox.c1214
1 files changed, 1214 insertions, 0 deletions
diff --git a/src/sandbox-dev/libsandbox.c b/src/sandbox-dev/libsandbox.c
new file mode 100644
index 00000000..ffb50359
--- /dev/null
+++ b/src/sandbox-dev/libsandbox.c
@@ -0,0 +1,1214 @@
+/*
+ * 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=<prefix> --host=<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 <gbevin@uwyn.com>
+ *
+ * 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 <brad@mainstreetsoftworks.com>.
+ *
+ * Martin Schlemmer <azarah@gentoo.org> (18 Aug 2002)
+ *
+ * Partly Copyright (C) 1998-9 Pancrazio `Ezio' de Mauro <p@demauro.net>,
+ * 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 <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <utime.h>
+#include <semaphore.h>
+
+#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