From d9fc4acc572c6647a4f27b838d35d27d805d190e Mon Sep 17 00:00:00 2001 From: Jason Stubbs Date: Sun, 28 Aug 2005 08:37:44 +0000 Subject: Migration (without history) of the current stable line to subversion. svn path=/main/branches/2.0/; revision=1941 --- src/sandbox/Makefile | 30 + src/sandbox/libsandbox.c | 873 +++++++++++++++++++++++++++ src/sandbox/problems/Makefile | 31 + src/sandbox/problems/libsandbox_emacsbug.c | 34 ++ src/sandbox/problems/libsandbox_muttbug.c | 24 + src/sandbox/problems/sandbox_dev_fd_foo.c | 42 ++ src/sandbox/problems/sandbox_muttbug.c | 43 ++ src/sandbox/sandbox.bashrc | 8 + src/sandbox/sandbox.c | 921 +++++++++++++++++++++++++++++ 9 files changed, 2006 insertions(+) create mode 100644 src/sandbox/Makefile create mode 100644 src/sandbox/libsandbox.c create mode 100644 src/sandbox/problems/Makefile create mode 100644 src/sandbox/problems/libsandbox_emacsbug.c create mode 100644 src/sandbox/problems/libsandbox_muttbug.c create mode 100644 src/sandbox/problems/sandbox_dev_fd_foo.c create mode 100644 src/sandbox/problems/sandbox_muttbug.c create mode 100644 src/sandbox/sandbox.bashrc create mode 100644 src/sandbox/sandbox.c (limited to 'src/sandbox') 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 +# +# Modified 15 Apr 2002 Jon Nelson +# 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= --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 +** $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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#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 +# +# Modified 15 Apr 2002 Jon Nelson +# 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 +# include +# include +# include +# include +# include +#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 +#include +#include +#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 +#include +#include +#include +#include + +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 +#include +#include + +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 +# $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= --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 +** $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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + } + } +} -- cgit v1.2.3-1-g7c22