summaryrefslogtreecommitdiffstats
path: root/src/sandbox
diff options
context:
space:
mode:
Diffstat (limited to 'src/sandbox')
-rw-r--r--src/sandbox/Makefile30
-rw-r--r--src/sandbox/libsandbox.c873
-rw-r--r--src/sandbox/problems/Makefile31
-rw-r--r--src/sandbox/problems/libsandbox_emacsbug.c34
-rw-r--r--src/sandbox/problems/libsandbox_muttbug.c24
-rw-r--r--src/sandbox/problems/sandbox_dev_fd_foo.c42
-rw-r--r--src/sandbox/problems/sandbox_muttbug.c43
-rw-r--r--src/sandbox/sandbox.bashrc8
-rw-r--r--src/sandbox/sandbox.c921
9 files changed, 2006 insertions, 0 deletions
diff --git a/src/sandbox/Makefile b/src/sandbox/Makefile
new file mode 100644
index 000000000..9c8fe9603
--- /dev/null
+++ b/src/sandbox/Makefile
@@ -0,0 +1,30 @@
+# 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>
+#
+# Modified 15 Apr 2002 Jon Nelson <jnelson@gentoo.org>
+# Clean up Makefile somewhat, and use make's implicit rules
+#
+# $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/Attic/Makefile,v 1.5 2002/08/05 16:44:34 drobbins Exp $
+
+.SUFFIXES:
+.SUFFIXES: .c .o .so
+.PRECIOUS: %.o
+
+%.so: LIBS=-ldl
+%.so: LDFLAGS=--shared
+%.so: %.o
+ $(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LIBS) $(LDFLAGS)
+
+CC = gcc
+CFLAGS = -Wall -O0 -fPIC
+LIBS =
+LDFLAGS =
+
+TARGETS = sandbox libsandbox.so
+
+all: $(TARGETS)
+
+clean:
+ rm -f $(TARGETS)
+ rm -f *.o *~
diff --git a/src/sandbox/libsandbox.c b/src/sandbox/libsandbox.c
new file mode 100644
index 000000000..d850554c3
--- /dev/null
+++ b/src/sandbox/libsandbox.c
@@ -0,0 +1,873 @@
+/*
+** 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>
+** $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/Attic/libsandbox.c,v 1.8 2002/08/05 05:51:39 drobbins Exp $
+*/
+
+#define _GNU_SOURCE
+#define _REENTRANT
+
+#define open xxx_open
+#define open64 xxx_open64
+# 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 <unistd.h>
+# include <utime.h>
+#undef open
+#undef open64
+
+#define PIDS_FILE "/tmp/sandboxpids.tmp"
+
+typedef struct {
+ int show_access_violation;
+ char** deny_prefixes;
+ int num_deny_prefixes;
+ char** read_prefixes;
+ int num_read_prefixes;
+ char** write_prefixes;
+ int num_write_prefixes;
+ char** predict_prefixes;
+ int num_predict_prefixes;
+ char** write_denied_prefixes;
+ int num_write_denied_prefixes;
+} sbcontext_t;
+
+int check_access(sbcontext_t*, const char*, const char*);
+int check_syscall(sbcontext_t*, const char*, const char*);
+int before_syscall(const char*, const char*);
+int before_syscall_open_int(const char*, const char*, int);
+int before_syscall_open_char(const char*, const char*, const char*);
+void clean_env_entries(char***, int*);
+char* filter_path(const char*);
+void* get_dl_symbol(char*);
+void init_context(sbcontext_t*);
+void init_env_entries(char***, int*, char*, int);
+int is_sandbox_on();
+int is_sandbox_pid();
+
+/* Wrapper macros and functions */
+
+/* macro definition to wrap functions before and after the
+ execution of basic file related system-calls.
+
+ nr : the argument number of the system-call's argument that
+ contains the file name to monitor
+ rt : the return type of the system call
+ name : the name of the function call
+ arg1, arg2, arg3 : the types of the function call's arguments
+ fl : the argument number of the system-call's argument that
+ contains the file access flags
+ md : the argument number of the system-call's argument that
+ contains the file access mode
+*/
+#define wrsysc3(nr, rt, name, arg1, arg2, arg3) \
+ \
+/* the function call is defined externally from this file */ \
+extern rt name(arg1, arg2, arg3); \
+ \
+/* orig_ ## name is a pointer to a function with three arguments and the
+ return type of the system call. This will be used to store the pointer
+ to the system call function and call it. */ \
+rt (*orig_ ## name)(arg1, arg2, arg3) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2, arg3 a3) \
+{ \
+ rt result = -1; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1, a2, a3); \
+ } \
+ return result; \
+}
+
+#define wrsysc2(nr, rt, name, arg1, arg2) \
+extern rt name(arg1, arg2); \
+rt (*orig_ ## name)(arg1, arg2) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2) \
+{ \
+ rt result = -1; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1, a2); \
+ } \
+ return result; \
+}
+
+#define wrsysc1(nr, rt, name, arg1) \
+extern rt name(arg1); \
+rt (*orig_ ## name)(arg1) = NULL; \
+ \
+rt name(arg1 a1) \
+{ \
+ rt result = -1; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1); \
+ } \
+ return result; \
+}
+
+#define wrsysc1ptr(nr, rt, name, arg1) \
+extern rt name(arg1); \
+rt (*orig_ ## name)(arg1) = NULL; \
+ \
+rt name(arg1 a1) \
+{ \
+ rt result = NULL; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1); \
+ } \
+ return result; \
+}
+
+#define wropenint3(nr, fl, rt, name, arg1, arg2, arg3) \
+extern rt name(arg1, arg2, arg3); \
+rt (*orig_ ## name)(arg1, arg2, arg3) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2, arg3 a3) \
+{ \
+ rt result = -1; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || \
+ 1 == before_syscall_open_int(#name, a ## nr, a ## fl)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1, a2, a3); \
+ } \
+ return result; \
+}
+
+#define wropenchar2(nr, md, rt, name, arg1, arg2) \
+extern rt name(arg1, arg2); \
+rt (*orig_ ## name)(arg1, arg2) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2) \
+{ \
+ rt result = NULL; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || \
+ 1 == before_syscall_open_char(#name, a ## nr, a ## md)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1, a2); \
+ } \
+ return result; \
+}
+
+#define wropenchar3(nr, md, rt, name, arg1, arg2, arg3) \
+extern rt name(arg1, arg2, arg3); \
+rt (*orig_ ## name)(arg1, arg2, arg3) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2, arg3 a3) \
+{ \
+ rt result = NULL; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || \
+ 1 == before_syscall_open_char(#name, a ## nr, a ## md)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1, a2, a3); \
+ } \
+ return result; \
+}
+
+#define wrexec3(nr, rt, name, arg1, arg2, arg3) \
+extern rt name(arg1, arg2, arg3); \
+rt (*orig_ ## name)(arg1, arg2, arg3) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2, arg3 a3) \
+{ \
+ rt result = -1; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1, a2, a3); \
+ } \
+ return result; \
+}
+
+#define wrexec2(nr, rt, name, arg1, arg2) \
+extern rt name(arg1, arg2); \
+rt (*orig_ ## name)(arg1, arg2) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2) \
+{ \
+ rt result = -1; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1, a2); \
+ } \
+ return result; \
+}
+
+#define wrexec2va(nr, rt, name, arg1, arg2) \
+extern rt name(arg1, arg2, ...); \
+rt (*orig_ ## name)(arg1, arg2, ...) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2, ...) \
+{ \
+ void* result = NULL; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = __builtin_apply( (void(*)()) orig_ ## name, \
+ __builtin_apply_args(), 32 ); \
+ old_errno = errno; \
+ } \
+ if (NULL == result) \
+ { \
+ return -1; \
+ } \
+ else \
+ { \
+ __builtin_return(result); \
+ } \
+}
+
+wropenint3(1, 2, int, open, const char*, int, mode_t)
+wropenint3(1, 2, int, open64, const char*, int, mode_t)
+
+wropenchar2(1, 2, FILE*, fopen, const char*, const char*)
+wropenchar2(1, 2, FILE*, fopen64, const char*, const char*)
+wropenchar3(1, 2, FILE*, freopen, const char*, const char*, FILE*)
+
+wropenchar2(1, 2, FILE*, popen, const char*, const char*)
+
+// write syscalls
+
+wrsysc2(1, int, creat, const char*, mode_t)
+wrsysc2(1, int, creat64, const char*, mode_t)
+
+wrsysc2(1, int, mkdir, const char*, mode_t)
+wrsysc3(1, int, mknod, const char*, mode_t, dev_t)
+wrsysc2(1, int, mkfifo, const char*, mode_t)
+
+wrsysc2(2, int, link, const char*, const char*)
+wrsysc2(2, int, symlink, const char*, const char*)
+wrsysc2(2, int, rename, const char*, const char*)
+
+wrsysc2(1, int, utime, const char*, const struct utimbuf*)
+wrsysc2(1, int, utimes, const char*, struct timeval*)
+
+wrsysc1(1, int, unlink, const char*)
+wrsysc1(1, int, rmdir, const char*)
+
+wrsysc3(1, int, chown, const char*, uid_t, gid_t)
+wrsysc3(1, int, lchown, const char*, uid_t, gid_t)
+
+wrsysc2(1, int, chmod, const char*, mode_t)
+
+/* read syscalls */
+
+wrsysc1ptr(1, DIR*, opendir, const char*)
+
+/* execution syscalls */
+wrsysc1(1, int, system, const char*)
+
+wrexec2va(1, int, execl, const char*, const char*)
+wrexec2va(1, int, execle, const char*, const char*)
+wrexec2(1, int, execv, const char*, char* const*)
+wrexec3(1, int, execve, const char*, char* const*, char* const*)
+/* execlp is redirected to execvp */
+/* execvp is special since it should search the PATH var entries */
+extern int execvp(const char*, char* const*);
+int(*orig_execvp)(const char*, char* const*) = NULL;
+int execvp(const char* file, char* const* argv)
+{
+ int result = -1;
+ int old_errno = errno;
+ int i = 0;
+ int allowed = 1;
+ char** path_entries = NULL;
+ int num_path_entries = 0;
+ char constructed_path[255];
+
+ if (1 == is_sandbox_on())
+ {
+ init_env_entries(&path_entries, &num_path_entries, "PATH", 0);
+ for (i = 0; i < num_path_entries; i++)
+ {
+ strcpy(constructed_path, path_entries[i]);
+ strcat(constructed_path, "/");
+ strcat(constructed_path, file);
+ if (0 == before_syscall("execvp", constructed_path))
+ {
+ allowed = 0;
+ break;
+ }
+ }
+ clean_env_entries(&path_entries, &num_path_entries);
+ }
+
+ if (1 == allowed)
+ {
+ if (!orig_execvp)
+ {
+ orig_execvp = get_dl_symbol("execvp");
+ }
+ errno = old_errno;
+ result = orig_execvp(file, argv);
+ old_errno = errno;
+ }
+ errno = old_errno;
+ return result;
+}
+
+/* lseek, lseek64, fdopen, fchown, fchmod, fcntl, lockf
+ are not wrapped since they can't be used if open is wrapped correctly
+ and unaccessible file descriptors are not possible to create */
+
+void* get_dl_symbol(char* symname)
+{
+ void* result = dlsym(RTLD_NEXT, symname);
+ if (0 == result)
+ {
+ fprintf(stderr, "Sandbox : can't resolve %s: %s.\n", symname, dlerror());
+ abort();
+ }
+ return result;
+}
+
+void init_context(sbcontext_t* context)
+{
+ context->show_access_violation = 1;
+ context->deny_prefixes = NULL;
+ context->num_deny_prefixes = 0;
+ context->read_prefixes = NULL;
+ context->num_read_prefixes = 0;
+ context->write_prefixes = NULL;
+ context->num_write_prefixes = 0;
+ context->predict_prefixes = NULL;
+ context->num_predict_prefixes = 0;
+ context->write_denied_prefixes = NULL;
+ context->num_write_denied_prefixes = 0;
+}
+
+int is_sandbox_pid()
+{
+ int result = 0;
+ FILE* pids_stream = NULL;
+ int pids_file = -1;
+ int current_pid = 0;
+ int tmp_pid = 0;
+
+ pids_stream = 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;
+ }
+
+ return result;
+}
+
+void clean_env_entries(char*** prefixes_array, int* prefixes_num)
+{
+ int i = 0;
+ if (NULL != *prefixes_array)
+ {
+ for (i = 0; i < *prefixes_num; i++)
+ {
+ if (NULL != (*prefixes_array)[i])
+ {
+ free((*prefixes_array)[i]);
+ (*prefixes_array)[i] = NULL;
+ }
+ }
+ free(*prefixes_array);
+ *prefixes_array = NULL;
+
+ *prefixes_num = 0;
+ }
+}
+
+void init_env_entries(char*** prefixes_array, int* prefixes_num, char* env, int warn)
+{
+ char* prefixes_env = getenv(env);
+
+ if (NULL == prefixes_env)
+ {
+ fprintf(stderr, "Sandbox error : the %s environmental variable should be defined.\n", env);
+ }
+ else
+ {
+ char* buffer = NULL;
+ int prefixes_env_length = strlen(prefixes_env);
+ int i = 0;
+ int num_delimiters = 0;
+ char* token = NULL;
+ char* prefix = NULL;
+
+ for (i = 0; i < prefixes_env_length; i++)
+ {
+ if (':' == prefixes_env[i])
+ {
+ num_delimiters++;
+ }
+ }
+
+ if (num_delimiters > 0)
+ {
+ buffer = (char*)malloc(sizeof(char)*(prefixes_env_length+1));
+ *prefixes_array = (char**)malloc(sizeof(char*)*(num_delimiters+1));
+
+ strcpy(buffer, prefixes_env);
+ token = strtok(buffer, ":");
+ while (NULL != token &&
+ strlen(token) > 0)
+ {
+ prefix = (char*)malloc(sizeof(char)*(strlen(token)+1));
+ strcpy(prefix, token);
+ (*prefixes_array)[(*prefixes_num)++] = filter_path(prefix);
+ free(prefix);
+ token = strtok(NULL, ":");
+ }
+ free(buffer);
+ buffer = NULL;
+ }
+ else if(prefixes_env_length > 0)
+ {
+ (*prefixes_array) = (char**)malloc(sizeof(char*));
+
+ prefix = (char*)malloc(sizeof(char)*(prefixes_env_length+1));
+ strcpy(prefix, prefixes_env);
+ (*prefixes_array)[(*prefixes_num)++] = filter_path(prefix);
+ free(prefix);
+ }
+ }
+}
+
+char* filter_path(const char* path)
+{
+ int initial_path_length = strlen(path);
+ char* filtered_path = (char*)malloc(sizeof(char)*(initial_path_length+1));
+ int i = 0;
+ int j = 0;
+
+ for (i = 0, j = 0; i < initial_path_length;)
+ {
+ filtered_path[j] = path[i];
+ if ('/' == filtered_path[j])
+ {
+ while ('/' == path[i] &&
+ i < initial_path_length)
+ {
+ i++;
+ }
+ }
+ else
+ {
+ i++;
+ }
+ j++;
+ }
+ filtered_path[j] = 0;
+
+ return filtered_path;
+}
+
+int check_access(sbcontext_t* sbcontext, const char* func, const char* path)
+{
+ int result = -1;
+ int i = 0;
+ char* filtered_path = filter_path(path);
+
+ if ('/' != path[0])
+ {
+ return 0;
+ }
+
+ if (0 == strcmp(filtered_path, "/etc/ld.so.preload") &&
+ is_sandbox_pid())
+ {
+ result = 1;
+ }
+
+ if (-1 == result)
+ {
+ if (NULL != sbcontext->deny_prefixes)
+ {
+ for (i = 0; i < sbcontext->num_deny_prefixes; i++)
+ {
+ if (0 == strncmp(filtered_path, sbcontext->deny_prefixes[i], strlen(sbcontext->deny_prefixes[i])))
+ {
+ result = 0;
+ break;
+ }
+ }
+ }
+
+ if (-1 == result)
+ {
+ if (NULL != sbcontext->read_prefixes &&
+ (0 == strcmp(func, "open_rd") ||
+ 0 == strcmp(func, "popen") ||
+ 0 == strcmp(func, "opendir") ||
+ 0 == strcmp(func, "system") ||
+ 0 == strcmp(func, "execl") ||
+ 0 == strcmp(func, "execlp") ||
+ 0 == strcmp(func, "execle") ||
+ 0 == strcmp(func, "execv") ||
+ 0 == strcmp(func, "execvp") ||
+ 0 == strcmp(func, "execve")))
+ {
+ for (i = 0; i < sbcontext->num_read_prefixes; i++)
+ {
+ if (0 == strncmp(filtered_path, sbcontext->read_prefixes[i], strlen(sbcontext->read_prefixes[i])))
+ {
+ result = 1;
+ break;
+ }
+ }
+ }
+ else if (NULL != sbcontext->write_prefixes &&
+ (0 == strcmp(func, "open_wr") ||
+ 0 == strcmp(func, "creat") ||
+ 0 == strcmp(func, "creat64") ||
+ 0 == strcmp(func, "mkdir") ||
+ 0 == strcmp(func, "mknod") ||
+ 0 == strcmp(func, "mkfifo") ||
+ 0 == strcmp(func, "link") ||
+ 0 == strcmp(func, "symlink") ||
+ 0 == strcmp(func, "rename") ||
+ 0 == strcmp(func, "utime") ||
+ 0 == strcmp(func, "utimes") ||
+ 0 == strcmp(func, "unlink") ||
+ 0 == strcmp(func, "rmdir") ||
+ 0 == strcmp(func, "chown") ||
+ 0 == strcmp(func, "lchown") ||
+ 0 == strcmp(func, "chmod")))
+ {
+ struct stat tmp_stat;
+
+ for (i = 0; i < sbcontext->num_write_denied_prefixes; i++)
+ {
+ if (0 == strncmp(filtered_path, sbcontext->write_denied_prefixes[i], strlen(sbcontext->write_denied_prefixes[i])))
+ {
+ result = 0;
+ break;
+ }
+ }
+ if (-1 == result)
+ {
+ for (i = 0; i < sbcontext->num_write_prefixes; i++)
+ {
+ if (0 == strncmp(filtered_path, sbcontext->write_prefixes[i], strlen(sbcontext->write_prefixes[i])))
+ {
+ result = 1;
+ break;
+ }
+ }
+
+ if (-1 == result)
+ {
+ /* hack to prevent mkdir of existing dirs to show errors */
+ if (strcmp(func, "mkdir") == 0)
+ {
+ if (0 == stat(filtered_path, &tmp_stat))
+ {
+ sbcontext->show_access_violation = 0;
+ result = 0;
+ }
+ }
+
+ if (-1 == result)
+ {
+ for (i = 0; i < sbcontext->num_predict_prefixes; i++)
+ {
+ if (0 == strncmp(filtered_path, sbcontext->predict_prefixes[i], strlen(sbcontext->predict_prefixes[i])))
+ {
+ sbcontext->show_access_violation = 0;
+ result = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (-1 == result)
+ {
+ result = 0;
+ }
+
+ free(filtered_path);
+
+ return result;
+}
+
+int check_syscall(sbcontext_t* sbcontext, const char* func, const char* file)
+{
+ int result = 1;
+ char* absolute_path = NULL;
+ char* tmp_buffer = NULL;
+ struct stat log_stat;
+ char* log_path = 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];
+
+ if ('/' == file[0])
+ {
+ absolute_path = (char*)malloc(sizeof(char)*(strlen(file)+1));
+ sprintf(absolute_path, "%s", file);
+ }
+ else
+ {
+ tmp_buffer = get_current_dir_name();
+ absolute_path = (char*)malloc(sizeof(char)*(strlen(tmp_buffer)+1+strlen(file)+1));
+ sprintf(absolute_path,"%s/%s", tmp_buffer, file);
+ 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 != strcmp(absolute_path, log_path)) &&
+ (NULL == debug_log_env || NULL == debug_log_path || 0 != strcmp(absolute_path, 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 = 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 != strcmp(absolute_path, 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 = 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);
+ }
+ }
+
+ free(absolute_path);
+ absolute_path = NULL;
+
+ return result;
+}
+
+int is_sandbox_on()
+{
+ /* $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 == strcmp(getenv("SANDBOX_ON"), "1") &&
+ NULL != getenv("SANDBOX_ACTIVE") &&
+ 0 == strcmp(getenv("SANDBOX_ACTIVE"), "armedandready"))
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+int before_syscall(const char* func, const char* file)
+{
+ int result = 1;
+
+ sbcontext_t sbcontext;
+
+ init_context(&sbcontext);
+
+ init_env_entries(&(sbcontext.deny_prefixes), &(sbcontext.num_deny_prefixes), "SANDBOX_DENY", 1);
+ init_env_entries(&(sbcontext.read_prefixes), &(sbcontext.num_read_prefixes), "SANDBOX_READ", 1);
+ init_env_entries(&(sbcontext.write_prefixes), &(sbcontext.num_write_prefixes), "SANDBOX_WRITE", 1);
+ init_env_entries(&(sbcontext.predict_prefixes), &(sbcontext.num_predict_prefixes), "SANDBOX_PREDICT", 1);
+
+ result = check_syscall(&sbcontext, func, file);
+
+ clean_env_entries(&(sbcontext.deny_prefixes), &(sbcontext.num_deny_prefixes));
+ clean_env_entries(&(sbcontext.read_prefixes), &(sbcontext.num_read_prefixes));
+ clean_env_entries(&(sbcontext.write_prefixes), &(sbcontext.num_write_prefixes));
+ clean_env_entries(&(sbcontext.predict_prefixes), &(sbcontext.num_predict_prefixes));
+
+ if (0 == result)
+ {
+ errno = EACCES;
+ }
+
+ return result;
+}
+
+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);
+ }
+}
+
+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);
+ }
+}
diff --git a/src/sandbox/problems/Makefile b/src/sandbox/problems/Makefile
new file mode 100644
index 000000000..b44189bdc
--- /dev/null
+++ b/src/sandbox/problems/Makefile
@@ -0,0 +1,31 @@
+# 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>
+#
+# Modified 15 Apr 2002 Jon Nelson <jnelson@gentoo.org>
+# Clean up Makefile somewhat, and use make's implicit rules
+#
+# $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/problems/Attic/Makefile,v 1.2 2002/04/16 01:06:55 jnelson Exp $
+
+.SUFFIXES:
+.SUFFIXES: .c .o .so
+.PRECIOUS: %.o
+
+%.so: LIBS=-ldl
+%.so: LDFLAGS=--shared
+%.so: %.o
+ $(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LIBS) $(LDFLAGS)
+
+CC = gcc
+CFLAGS = -Wall -O2
+LIBS =
+LDFLAGS =
+
+TARGETS = sandbox_muttbug sandbox_dev_fd_foo \
+ libsandbox_muttbug.so libsandbox_emacsbug.so
+
+all: $(TARGETS)
+
+clean:
+ rm -f $(TARGETS)
+ rm -f *.o *~
diff --git a/src/sandbox/problems/libsandbox_emacsbug.c b/src/sandbox/problems/libsandbox_emacsbug.c
new file mode 100644
index 000000000..11e861b92
--- /dev/null
+++ b/src/sandbox/problems/libsandbox_emacsbug.c
@@ -0,0 +1,34 @@
+/* $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/problems/Attic/libsandbox_emacsbug.c,v 1.2 2003/03/22 14:24:38 carpaski Exp $ */
+
+#define _GNU_SOURCE
+#define _REENTRANT
+
+#define open xxx_open
+# include <dlfcn.h>
+# include <errno.h>
+# include <fcntl.h>
+# include <stdlib.h>
+# include <sys/stat.h>
+# include <sys/types.h>
+#undef open
+
+extern int open(const char*, int, mode_t);
+int (*orig_open)(const char*, int, mode_t) = NULL;
+int open(const char* pathname, int flags, mode_t mode)
+{
+ int old_errno = errno;
+
+ /* code that makes xemacs' compilation produce a segfaulting executable */
+/* char** test = NULL;
+ test = (char**)malloc(sizeof(char*));
+ free(test);*/
+ /* end of that code */
+
+ if (!orig_open)
+ {
+ orig_open = dlsym(RTLD_NEXT, "open");
+ }
+ errno = old_errno;
+ return orig_open(pathname, flags, mode);
+}
+
diff --git a/src/sandbox/problems/libsandbox_muttbug.c b/src/sandbox/problems/libsandbox_muttbug.c
new file mode 100644
index 000000000..1d6e18c48
--- /dev/null
+++ b/src/sandbox/problems/libsandbox_muttbug.c
@@ -0,0 +1,24 @@
+/* $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/problems/Attic/libsandbox_muttbug.c,v 1.2 2003/03/22 14:24:38 carpaski Exp $ */
+
+#define _GNU_SOURCE
+#define _REENTRANT
+
+#define open xxx_open
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdio.h>
+#undef open
+
+extern FILE* fopen(const char*, const char*);
+FILE* (*orig_fopen)(const char*, const char*) = 0;
+FILE* fopen(const char* a1, const char* a2)
+{
+ int old_errno = errno;
+ if (!orig_fopen)
+ {
+ orig_fopen = dlsym(RTLD_NEXT, "fopen");
+ }
+ errno = old_errno;
+ return orig_fopen(a1, a2);
+}
+
diff --git a/src/sandbox/problems/sandbox_dev_fd_foo.c b/src/sandbox/problems/sandbox_dev_fd_foo.c
new file mode 100644
index 000000000..c36a095c2
--- /dev/null
+++ b/src/sandbox/problems/sandbox_dev_fd_foo.c
@@ -0,0 +1,42 @@
+/* $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/problems/Attic/sandbox_dev_fd_foo.c,v 1.2 2003/03/22 14:24:38 carpaski Exp $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+void cleanup_1(void)
+{
+ puts("Unlinking file...");
+ unlink("/tmp/_sandbox_test.file");
+}
+
+int main(void)
+{
+ struct stat s1, s2;
+ FILE *fp1, *fp2;
+ char *file = "/tmp/_sandbox_test.file";
+ char devfd[32];
+
+ printf("Opening file...\n");
+ if (!(fp1 = fopen(file, "w")))
+ exit(1);
+ atexit(cleanup_1);
+ printf("fstat'ing file...\n");
+ if (fstat(fileno(fp1), &s1) < 0)
+ exit(2);
+ sprintf(devfd, "/dev/fd/%d", fileno(fp1));
+ printf("fopening %s...\n", devfd);
+ if (!(fp2 = fopen(devfd, "w")))
+ exit(3);
+ printf("fstat'ing %s...\n", devfd);
+ if (fstat(fileno(fp2), &s2) < 0)
+ exit(4);
+ printf("Checking %ld == %ld and %ld == %ld...\n",
+ (long int) s1.st_dev, (long int) s2.st_dev, s1.st_ino, s2.st_ino);
+ if (s1.st_dev != s2.st_dev || s1.st_ino != s2.st_ino)
+ exit(5);
+ printf("Success!\n");
+ return(0);
+}
diff --git a/src/sandbox/problems/sandbox_muttbug.c b/src/sandbox/problems/sandbox_muttbug.c
new file mode 100644
index 000000000..cccdc43ee
--- /dev/null
+++ b/src/sandbox/problems/sandbox_muttbug.c
@@ -0,0 +1,43 @@
+/* $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/problems/Attic/sandbox_muttbug.c,v 1.3 2003/03/22 14:24:38 carpaski Exp $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ FILE *fd ;
+
+ printf("unlink\n");
+ unlink("/tmp/test");
+ printf("... done\n");
+
+ printf("fopen\n");
+ fd = fopen("/tmp/test", "a+");
+ printf("... done\n");
+
+ printf("fputc\n");
+ fputc('7', fd);
+ printf("... done\n");
+
+ printf("fseek\n");
+ fseek(fd, 0, SEEK_SET);
+ printf("... done\n");
+
+ printf("freopen\n");
+ fd = freopen("/tmp/test", "r", fd);
+ printf("... done\n");
+
+ printf("fgetc ");
+ printf("%c\n", fgetc(fd));
+ printf("... done\n");
+
+ printf("fseek\n");
+ fseek(fd, 0, SEEK_SET);
+ printf("... done\n");
+
+ printf("fclose\n");
+ fclose(fd);
+ printf("... done\n");
+ return 0;
+}
diff --git a/src/sandbox/sandbox.bashrc b/src/sandbox/sandbox.bashrc
new file mode 100644
index 000000000..be25349db
--- /dev/null
+++ b/src/sandbox/sandbox.bashrc
@@ -0,0 +1,8 @@
+# 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>
+# $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/Attic/sandbox.bashrc,v 1.2 2002/03/06 09:51:02 gbevin Exp $
+source /etc/profile
+export LD_PRELOAD="$SANDBOX_LIB"
+alias make="make LD_PRELOAD=$SANDBOX_LIB"
+alias su="su -c '/bin/bash -rcfile $SANDBOX_DIR/sandbox.bashrc'"
diff --git a/src/sandbox/sandbox.c b/src/sandbox/sandbox.c
new file mode 100644
index 000000000..5a2295e79
--- /dev/null
+++ b/src/sandbox/sandbox.c
@@ -0,0 +1,921 @@
+/*
+** 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>
+** $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/Attic/sandbox.c,v 1.13 2002/08/05 05:51:39 drobbins Exp $
+*/
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define LD_PRELOAD_FILE "/etc/ld.so.preload"
+#define LIB_NAME "libsandbox.so"
+#define BASHRC_NAME "sandbox.bashrc"
+#define PIDS_FILE "/tmp/sandboxpids.tmp"
+#define LOG_FILE_PREFIX "/tmp/sandbox-"
+#define DEBUG_LOG_FILE_PREFIX "/tmp/sandbox-debug-"
+#define LOG_FILE_EXT ".log"
+
+#define ENV_SANDBOX_DEBUG_LOG "SANDBOX_DEBUG_LOG"
+#define ENV_SANDBOX_LOG "SANDBOX_LOG"
+#define ENV_SANDBOX_DIR "SANDBOX_DIR"
+#define ENV_SANDBOX_LIB "SANDBOX_LIB"
+
+#define ENV_SANDBOX_DENY "SANDBOX_DENY"
+#define ENV_SANDBOX_READ "SANDBOX_READ"
+#define ENV_SANDBOX_WRITE "SANDBOX_WRITE"
+#define ENV_SANDBOX_PREDICT "SANDBOX_PREDICT"
+
+#define ENV_SANDBOX_ON "SANDBOX_ON"
+#define ENV_SANDBOX_BEEP "SANDBOX_BEEP"
+
+#define DEFAULT_BEEP_COUNT 3
+
+int preload_adaptable = 1;
+int cleaned_up = 0;
+
+char* dirname(const char* path)
+{
+ char* base = NULL;
+ unsigned int length = 0;
+
+ base = strrchr(path, '/');
+ if (NULL == base)
+ {
+ return strdup(".");
+ }
+ while (base > path &&
+ *base == '/')
+ {
+ base--;
+ }
+ length = (unsigned int) 1 + base - path;
+
+ base = malloc(sizeof(char)*(length+1));
+ memmove(base, path, length);
+ base[length] = 0;
+
+ return base;
+}
+
+void cleanup()
+{
+ int i = 0;
+ int success = 1;
+
+ FILE* preload_stream = NULL;
+ int preload_file = -1;
+ char preload_entry[255];
+ char** preload_array = NULL;
+ int num_of_preloads = 0;
+
+ FILE* pids_stream = NULL;
+ struct stat pids_stat;
+ int pids_file = -1;
+ char pid_string[255];
+ int tmp_pid = 0;
+ int* pids_array = NULL;
+ int num_of_pids = 0;
+
+ /* remove this sandbox's bash pid from the global pids file if it has rights to adapt the ld.so.preload file*/
+ if (1 == preload_adaptable &&
+ 0 == cleaned_up)
+ {
+ cleaned_up = 1;
+ success = 1;
+ if (0 == lstat(PIDS_FILE, &pids_stat) &&
+ 0 == S_ISREG(pids_stat.st_mode))
+ {
+ perror(">>> pids file is not a regular file");
+ success = 0;
+ }
+ else
+ {
+ pids_stream = fopen(PIDS_FILE, "r+");
+ if (NULL == pids_stream)
+ {
+ perror(">>> pids file fopen");
+ success = 0;
+ }
+ else
+ {
+ pids_file = fileno(pids_stream);
+ if (pids_file < 0)
+ {
+ perror(">>> pids file fileno");
+ success = 0;
+ }
+ else
+ {
+ if (flock(pids_file, LOCK_EX) < 0)
+ {
+ perror(">>> pids file lock");
+ success = 0;
+ }
+ else
+ {
+ /* check which sandbox pids are still running */
+ while (EOF != fscanf(pids_stream, "%d\n", &tmp_pid))
+ {
+ if (0 == kill(tmp_pid, 0))
+ {
+ if (NULL == pids_array)
+ {
+ pids_array = (int*)malloc(sizeof(int));
+ }
+ else
+ {
+ pids_array = (int*)realloc(pids_array, sizeof(int)*(num_of_pids+1));
+ }
+ pids_array[num_of_pids++] = tmp_pid;
+ }
+ }
+
+ /* clean the /etc/ld.so.preload file if no other sandbox processes are running anymore*/
+ if(num_of_pids == 1)
+ {
+ success = 1;
+ preload_stream = fopen("/etc/ld.so.preload", "r+");
+ if (NULL == preload_stream)
+ {
+ perror(">>> /etc/ld.so.preload file fopen");
+ success = 0;
+ }
+ else
+ {
+ preload_file = fileno(preload_stream);
+ if (preload_file < 0)
+ {
+ perror(">>> /etc/ld.so.preload file fileno");
+ success = 0;
+ }
+ else
+ {
+ if (flock(preload_file, LOCK_EX) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file lock");
+ success = 0;
+ }
+ else
+ {
+ /* only get the entries that don't contain the sandbox library from the /etc/ld.so.preload file */
+ while (EOF != fscanf(preload_stream, "%s\n", preload_entry))
+ {
+ if (NULL == strstr(preload_entry, LIB_NAME))
+ {
+ if (NULL == preload_array)
+ {
+ preload_array = (char**)malloc(sizeof(char*));
+ }
+ else
+ {
+ preload_array = (char**)realloc(pids_array, sizeof(char*)*(num_of_preloads+1));
+ }
+ preload_array[num_of_preloads++] = strdup(preload_entry);
+ }
+ }
+
+ if (fseek(preload_stream, 0, SEEK_SET) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file fseek");
+ success = 0;
+ }
+ else
+ {
+ /* empty the /etc/ld.so.preload file */
+ if (ftruncate(preload_file, 0) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file ftruncate");
+ success = 0;
+ }
+ else
+ {
+ /* store the other preload libraries back into the /etc/ld.so.preload file */
+ if(num_of_preloads > 0)
+ {
+ for (i = 0; i < num_of_preloads; i++)
+ {
+ sprintf(preload_entry, "%s\n", preload_array[i]);
+ if (write(preload_file, preload_entry, strlen(preload_entry)) != strlen(preload_entry))
+ {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (NULL != preload_array)
+ {
+ for (i = 0; i < num_of_preloads; i++)
+ {
+ free(preload_array[i]);
+ preload_array[i] = NULL;
+ }
+ free(preload_array);
+ preload_array = NULL;
+ }
+
+ if (flock(preload_file, LOCK_UN) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file unlock");
+ success = 0;
+ }
+ }
+ }
+ if (EOF == fclose(preload_stream))
+ {
+ perror(">>> /etc/ld.so.preload file fclose");
+ success = 0;
+ }
+ preload_stream = NULL;
+ preload_file = -1;
+ }
+ }
+
+ if (fseek(pids_stream, 0, SEEK_SET) < 0)
+ {
+ perror(">>> pids file fseek");
+ success = 0;
+ }
+ else
+ {
+ /* empty the pids file */
+ if (ftruncate(pids_file, 0) < 0)
+ {
+ perror(">>> pids file ftruncate");
+ success = 0;
+ }
+ else
+ {
+ /* if pids are still running, write only the running pids back to the file */
+ if(num_of_pids > 1)
+ {
+ for (i = 0; i < num_of_pids; i++)
+ {
+ sprintf(pid_string, "%d\n", pids_array[i]);
+ if (write(pids_file, pid_string, strlen(pid_string)) != strlen(pid_string))
+ {
+ perror(">>> pids file write");
+ success = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (NULL != pids_array)
+ {
+ free(pids_array);
+ pids_array = NULL;
+ }
+
+ if (flock(pids_file, LOCK_UN) < 0)
+ {
+ perror(">>> pids file unlock");
+ success = 0;
+ }
+ }
+ }
+ if (EOF == fclose(pids_stream))
+ {
+ perror(">>> pids file fclose");
+ success = 0;
+ }
+ pids_stream = NULL;
+ pids_file = -1;
+ }
+ }
+ if (0 == success)
+ {
+ exit(1);
+ }
+ }
+}
+
+void stop(int signum)
+{
+ cleanup();
+}
+
+int main(int argc, char** argv)
+{
+ int i = 0;
+ int success = 1;
+ int status = 0;
+ char* run_str = "-c";
+ char run_arg[255];
+
+ struct stat preload_stat;
+ FILE* preload_stream = NULL;
+ int preload_file = -1;
+ char preload_entry[255];
+ int preload_lib_present = 0;
+
+ int bash_pid = 0;
+ char* home_dir = NULL;
+ char portage_tmp_dir[PATH_MAX];
+ char var_tmp_dir[PATH_MAX];
+ char tmp_dir[PATH_MAX];
+ char sandbox_write_var[255];
+ char sandbox_predict_var[255];
+ char* tmp_string = NULL;
+ char full_sandbox_path[255];
+ char sandbox_log[255];
+ char* sandbox_log_env;
+ struct stat sandbox_log_stat;
+ int sandbox_log_presence = 0;
+ int sandbox_log_file = -1;
+ char sandbox_debug_log[255];
+ char sandbox_dir[255];
+ char sandbox_lib[255];
+ struct stat sandbox_lib_stat;
+ char sandbox_rc[255];
+ struct stat sandbox_rc_stat;
+
+ struct stat pids_stat;
+ int pids_file = -1;
+ char pid_string[255];
+
+ // Only print info if called with no arguments ....
+ if (argc < 2)
+ {
+ printf("========================== Gentoo linux path sandbox ===========================\n");
+ }
+
+ /* check if a sandbox is already running */
+ if (NULL != getenv(ENV_SANDBOX_ON))
+ {
+ fprintf(stderr, "Not launching a new sandbox instance\nAnother one is already running in this process hierarchy.\n");
+
+ exit(1);
+ }
+ else
+ {
+ char* argv_bash[] =
+ {
+ "/bin/bash",
+ "-rcfile",
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ };
+
+ /* determine the location of all the sandbox support files */
+ if (argc < 2)
+ printf("Detection of the support files.\n");
+ if ('/' == argv[0][0])
+ {
+ strcpy(full_sandbox_path, argv[0]);
+ }
+ else
+ {
+ tmp_string = get_current_dir_name();
+ strcpy(full_sandbox_path, tmp_string);
+ free(tmp_string);
+ tmp_string = NULL;
+ strcat(full_sandbox_path, "/");
+ strcat(full_sandbox_path, argv[0]);
+ }
+ tmp_string = dirname(full_sandbox_path);
+ strcpy(sandbox_dir, tmp_string);
+ free(tmp_string);
+ tmp_string = NULL;
+ strcat(sandbox_dir, "/");
+ strcpy(sandbox_lib, "/lib/");
+ strcat(sandbox_lib, LIB_NAME);
+ if (-1 == stat(sandbox_lib, &sandbox_lib_stat))
+ {
+ strcpy(sandbox_lib, sandbox_dir);
+ strcat(sandbox_lib, LIB_NAME);
+ }
+ strcpy(sandbox_rc, "/usr/lib/portage/lib/");
+ strcat(sandbox_rc, BASHRC_NAME);
+ if (-1 == stat(sandbox_rc, &sandbox_rc_stat))
+ {
+ strcpy(sandbox_rc, sandbox_dir);
+ strcat(sandbox_rc, BASHRC_NAME);
+ }
+
+ /* verify the existance of required files */
+ if (argc < 2)
+ {
+ printf("Verification of the required files.\n");
+ }
+ if (-1 == stat(sandbox_lib, &sandbox_lib_stat))
+ {
+ fprintf(stderr, "Could not open the sandbox library at '%s'.\n", sandbox_lib);
+ return -1;
+ }
+ else if (-1 == stat(sandbox_rc, &sandbox_rc_stat))
+ {
+ fprintf(stderr, "Could not open the sandbox rc file at '%s'.\n", sandbox_rc);
+ return -1;
+ }
+ else
+ {
+ /* ensure that the /etc/ld.so.preload file contains an entry for the sandbox lib */
+ if (argc < 2)
+ {
+ printf("Setting up the ld.so.preload file.\n");
+ }
+
+ /* check if the /etc/ld.so.preload file exists */
+ if (stat("/etc/ld.so.preload", &preload_stat) < 0 &&
+ ENOENT == errno)
+ {
+ /* if not, try to create it and write the path of the sandbox lib to it */
+ success = 1;
+ preload_file = open("/etc/ld.so.preload", O_WRONLY|O_CREAT, 0644);
+ if (preload_file < 0)
+ {
+ /* if access was denied, warn the user about it */
+ if (EACCES == errno)
+ {
+ preload_adaptable = 0;
+ printf(">>> Couldn't adapt the /etc/ld.so.preload file.\n>>> It's possible that not all function calls are trapped\n");
+ }
+ else
+ {
+ perror(">>> /etc/ld.so.preload file open");
+ success = 0;
+ }
+ }
+ else
+ {
+ if (flock(preload_file, LOCK_EX) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file lock");
+ success = 0;
+ }
+ else
+ {
+ if (write(preload_file, sandbox_lib, strlen(sandbox_lib)) != strlen(sandbox_lib))
+ {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ }
+
+ if (flock(preload_file, LOCK_UN) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file unlock");
+ success = 0;
+ }
+ }
+ if (close(preload_file) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file close");
+ success = 0;
+ }
+ pids_file = -1;
+ }
+ if (0 == success)
+ {
+ exit(1);
+ }
+ }
+ else
+ {
+ /* if the /etc/ld.so.preload file exists, try to open it in read/write mode */
+ success = 1;
+ if (0 == S_ISREG(preload_stat.st_mode))
+ {
+ perror(">>> /etc/ld.so.preload file is not a regular file");
+ success = 0;
+ }
+ else
+ {
+ preload_stream = fopen("/etc/ld.so.preload", "r+");
+ if (NULL == preload_stream)
+ {
+ if (EACCES == errno)
+ {
+ /* if access was denied, warn the user about it */
+ preload_adaptable = 0;
+ printf(">>> Couldn't adapt the /etc/ld.so.preload file.\n>>> It's possible that not all function calls are trapped\n");
+ }
+ else
+ {
+ perror(">>> /etc/ld.so.preload file fopen");
+ success = 0;
+ }
+ }
+ else
+ {
+ preload_file = fileno(preload_stream);
+ if (preload_file < 0)
+ {
+ perror(">>> /etc/ld.so.preload file fileno");
+ success = 0;
+ }
+ else
+ {
+ if (flock(preload_file, LOCK_EX) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file lock");
+ success = 0;
+ }
+ else
+ {
+ /* check if the sandbox library is already present in the /etc/ld.so.preload file */
+ while (EOF != fscanf(preload_stream, "%s\n", preload_entry))
+ {
+ if (NULL != strstr(preload_entry, LIB_NAME))
+ {
+ preload_lib_present = 1;
+ break;
+ }
+ }
+
+ /* if it's not present, add the sandbox lib path to the end of the /etc/ld.so.preload file */
+ if (0 == preload_lib_present)
+ {
+ if (fseek(preload_stream, 0, SEEK_END) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file fseek");
+ success = 0;
+ }
+ else
+ {
+ if (write(preload_file, sandbox_lib, strlen(sandbox_lib)) != strlen(sandbox_lib))
+ {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ }
+ }
+ }
+
+ if (flock(preload_file, LOCK_UN) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file unlock");
+ success = 0;
+ }
+ }
+ }
+ if (EOF == fclose(preload_stream))
+ {
+ perror(">>> /etc/ld.so.preload file fclose");
+ success = 0;
+ }
+ preload_stream = NULL;
+ preload_file = -1;
+ }
+ }
+ if (0 == success)
+ {
+ exit(1);
+ }
+ }
+
+ /* set up the required environment variables */
+ if (argc < 2)
+ {
+ printf("Setting up the required environment variables.\n");
+ }
+ argv_bash[2] = sandbox_rc;
+
+ sprintf(pid_string, "%d", getpid());
+ strcpy(sandbox_log, LOG_FILE_PREFIX);
+ sandbox_log_env = getenv(ENV_SANDBOX_LOG);
+ if (sandbox_log_env)
+ {
+ strcat(sandbox_log, sandbox_log_env);
+ strcat(sandbox_log, "-");
+ }
+ strcat(sandbox_log, pid_string);
+ strcat(sandbox_log, LOG_FILE_EXT);
+ setenv(ENV_SANDBOX_LOG, sandbox_log, 1);
+ strcpy(sandbox_debug_log, DEBUG_LOG_FILE_PREFIX);
+ strcat(sandbox_debug_log, pid_string);
+ strcat(sandbox_debug_log, LOG_FILE_EXT);
+ setenv(ENV_SANDBOX_DEBUG_LOG, sandbox_debug_log, 1);
+ home_dir = getenv("HOME");
+
+ // drobbins: we need to expand these paths using realpath() so that PORTAGE_TMPDIR
+ // can contain symlinks (example, /var is a symlink, /var/tmp is a symlink.) Without
+ // this, access is denied to /var/tmp, hurtin' ebuilds.
+
+ realpath(getenv("PORTAGE_TMPDIR"),portage_tmp_dir);
+ realpath("/var/tmp",var_tmp_dir);
+ realpath("/tmp",tmp_dir);
+
+ setenv(ENV_SANDBOX_DIR, sandbox_dir, 1);
+ setenv(ENV_SANDBOX_LIB, sandbox_lib, 1);
+ setenv("LD_PRELOAD", sandbox_lib, 1);
+ if (NULL == getenv(ENV_SANDBOX_DENY))
+ {
+ setenv(ENV_SANDBOX_DENY, LD_PRELOAD_FILE, 1);
+ }
+ if (NULL == getenv(ENV_SANDBOX_READ))
+ {
+ setenv(ENV_SANDBOX_READ, "/", 1);
+ }
+ if (NULL == getenv(ENV_SANDBOX_WRITE))
+ {
+ /* these should go into make.globals later on */
+ strcpy(sandbox_write_var, "");
+ strcat(sandbox_write_var, "/dev/zero:/dev/fd/:/dev/null:/dev/pts/:/dev/vc/:/dev/tty:/tmp/");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/var/log/scrollkeeper.log");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, home_dir);
+ strcat(sandbox_write_var, "/.gconfd/lock");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, home_dir);
+ strcat(sandbox_write_var, "/.bash_history");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/usr/tmp/conftest");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/usr/lib/conftest");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/usr/tmp/cf");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/usr/lib/cf");
+ strcat(sandbox_write_var, ":");
+ if (NULL == portage_tmp_dir)
+ {
+ strcat(sandbox_write_var, tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, var_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/tmp/");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/var/tmp/");
+ }
+ else if (0 == strcmp(sandbox_write_var, "/var/tmp/"))
+ {
+ strcat(sandbox_write_var, portage_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/tmp/");
+ }
+ else if (0 == strcmp(sandbox_write_var, "/tmp/"))
+ {
+ strcat(sandbox_write_var, portage_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, var_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/var/tmp/");
+ }
+ else
+ {
+ strcat(sandbox_write_var, portage_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, var_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/tmp/");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/var/tmp/");
+ }
+ /* */
+ setenv(ENV_SANDBOX_WRITE, sandbox_write_var, 1);
+ }
+ if (NULL == getenv(ENV_SANDBOX_PREDICT))
+ {
+ /* these should go into make.globals later on */
+ strcpy(sandbox_predict_var, "");
+ strcat(sandbox_predict_var, home_dir);
+ strcat(sandbox_predict_var, "/.");
+ strcat(sandbox_predict_var, ":");
+ strcat(sandbox_predict_var, "/usr/lib/python2.0/");
+ strcat(sandbox_predict_var, ":");
+ strcat(sandbox_predict_var, "/usr/lib/python2.1/");
+ strcat(sandbox_predict_var, ":");
+ strcat(sandbox_predict_var, "/usr/lib/python2.2/");
+ setenv(ENV_SANDBOX_PREDICT, sandbox_predict_var, 1);
+ /* */
+ }
+ setenv(ENV_SANDBOX_ON, "1", 0);
+
+ /* if the portage temp dir was present, cd into it */
+ if (NULL != portage_tmp_dir)
+ {
+ chdir(portage_tmp_dir);
+ }
+
+ /* adding additional bash arguments */
+ for (i = 1; i < argc; i++)
+ {
+ if (1 == i)
+ {
+ argv_bash[3] = run_str;
+ argv_bash[4] = run_arg;
+ strcpy(argv_bash[4], argv[i]);
+ }
+ else
+ {
+ strcat(argv_bash[4], " ");
+ strcat(argv_bash[4], argv[i]);
+ }
+ }
+
+ /* set up the required signal handlers */
+ signal(SIGHUP, &stop);
+ signal(SIGINT, &stop);
+ signal(SIGQUIT, &stop);
+ signal(SIGTERM, &stop);
+
+ /* this one should NEVER be set in ebuilds, as it is the one
+ * private thing libsandbox.so use to test if the sandbox
+ * should be active for this pid, or not.
+ *
+ * azarah (3 Aug 2002)
+ */
+ setenv("SANDBOX_ACTIVE", "armedandready", 1);
+
+ /* fork to executing bash */
+ if (argc < 2)
+ {
+ printf("Creating a seperate process the run the shell in.\n");
+ }
+ bash_pid = fork();
+
+ if (0 == bash_pid)
+ {
+ /* launch bash */
+ execv(argv_bash[0], argv_bash);
+ }
+ else
+ {
+ int wait_pid = 0;
+
+ if (argc < 2)
+ {
+ printf("The protected environment has been started.\n");
+ printf("--------------------------------------------------------------------------------\n");
+ }
+
+ /* store his sandbox's bash pid in the global pids file if it has rights to adapt the ld.so.preload file*/
+ if (1 == preload_adaptable)
+ {
+ success = 1;
+ if (0 == lstat(PIDS_FILE, &pids_stat) &&
+ 0 == S_ISREG(pids_stat.st_mode))
+ {
+ perror(">>> pids file is not a regular file");
+ success = 0;
+ }
+ else
+ {
+ pids_file = open(PIDS_FILE, O_WRONLY|O_CREAT|O_APPEND, 0644);
+ if (pids_file < 0)
+ {
+ perror(">>> pids file open");
+ success = 0;
+ }
+ else
+ {
+ if (flock(pids_file, LOCK_EX) < 0)
+ {
+ perror(">>> pids file lock");
+ success = 0;
+ }
+ else
+ {
+ sprintf(pid_string, "%d\n", getpid());
+ if (write(pids_file, pid_string, strlen(pid_string)) != strlen(pid_string))
+ {
+ perror(">>> pids file write");
+ success = 0;
+ }
+
+ if (flock(pids_file, LOCK_UN) < 0)
+ {
+ perror(">>> pids file unlock");
+ success = 0;
+ }
+ }
+ if (close(pids_file) < 0)
+ {
+ perror(">>> pids file close");
+ success = 0;
+ }
+ pids_file = -1;
+ }
+ }
+ if (0 == success)
+ {
+ exit(1);
+ }
+ }
+
+ /* wait until bash exits */
+ wait_pid = waitpid(bash_pid, &status, 0);
+ }
+ }
+
+ cleanup();
+
+ if (argc < 2)
+ {
+ printf("========================== Gentoo linux path sandbox ===========================\n");
+ printf("The protected environment has been shut down.\n");
+ }
+ if (0 == stat(sandbox_log, &sandbox_log_stat))
+ {
+ sandbox_log_presence = 1;
+ success = 1;
+ sandbox_log_file = open(sandbox_log, O_RDONLY, 0);
+ if (sandbox_log_file < 0)
+ {
+ perror(">>> sandbox log file open");
+ success = 0;
+ }
+ else
+ {
+ int i = 0;
+ char* beep_count_env = NULL;
+ int beep_count = 0;
+ int length = 0;
+ char buffer[255];
+
+ printf("\e[31;01m--------------------------- ACCESS VIOLATION SUMMARY ---------------------------\033[0m\n");
+ printf("\e[31;01mLOG FILE = \"%s\"\033[0m\n", sandbox_log);
+ printf("\n");
+ while ((length = read(sandbox_log_file, buffer, sizeof(buffer)-1)) > 0)
+ {
+ if (length < sizeof(buffer))
+ {
+ buffer[length] = 0;
+ }
+ printf("%s", buffer);
+ }
+ printf("\e[31;01m--------------------------------------------------------------------------------\033[0m\n");
+
+ if (close(sandbox_log_file) < 0)
+ {
+ perror(">>> sandbox log close");
+ success = 0;
+ }
+
+ beep_count_env = getenv(ENV_SANDBOX_BEEP);
+ if (beep_count_env)
+ {
+ beep_count = atoi(beep_count_env);
+ }
+ else
+ {
+ beep_count = DEFAULT_BEEP_COUNT;
+ }
+ for (i = 0; i < beep_count; i++)
+ {
+ fputc('\a', stderr);
+ if (i < beep_count -1)
+ {
+ sleep(1);
+ }
+ }
+
+ }
+ if (0 == success)
+ {
+ exit(1);
+ }
+ sandbox_log_file = -1;
+ }
+ else if (argc < 2)
+ {
+ printf("--------------------------------------------------------------------------------\n");
+ }
+
+ if (status > 0 ||
+ 1 == sandbox_log_presence)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+}