[Darwinfiles-cvs] portage/src/sandbox-1.1 ChangeLog,NONE,1.1 Makefile,NONE,1.1 canonicalize.c,NONE,1
Status: Alpha
Brought to you by:
jimmacr
From: <ji...@us...> - 2002-09-08 16:21:15
|
Update of /cvsroot/darwinfiles/portage/src/sandbox-1.1 In directory usw-pr-cvs1:/tmp/cvs-serv32248 Added Files: ChangeLog Makefile canonicalize.c create-localdecls libctest.c libsandbox.c sandbox.bashrc sandbox.c sandbox.h sandbox_futils.c Log Message: Merged with portage-2.0.36 --- NEW FILE: ChangeLog --- # ChangeLog for Path Sandbox # Copyright 2002 Gentoo Technologies, Inc.; Distributed under the GPL v2 # $Header: /cvsroot/darwinfiles/portage/src/sandbox-1.1/ChangeLog,v 1.1 2002/09/08 16:21:12 jimmacr Exp $ 1 Sep 2002; Martin Schlemmer <az...@ge...> : Fix my braindead 'return 1;' in a void function. Updated sandbox.c, cleanup() for this. Change cleanup() in sandbox.c not to exit with fail status if the pidsfile is missing. We really should still display sandbox violations if they occured. 31 Aug 2002; Martin Schlemmer <az...@ge...> : Update cleanup() in sandbox.c to remove the PIDSFILE if this is the last sandbox running. 25 Aug 2002; Martin Schlemmer <az...@ge...> : Major cleanups to mainly libsandbox.c again. 22 Aug 2002; Martin Schlemmer <az...@ge...> : Add copyrights to sandbox.h and sandbox_futils.h. If wrong, the parties involved should please contact me so that we can fix it. Add opendir wrapper to libsandbox.c. 21 Aug 2002; Martin Schlemmer <az...@ge...> : Do some more cleanups to ecanonicalize(), as it dropped filenames in rare cases (after my symlink cleanups), and caused glibc to bork. These fixes went into canonicalize.c. 20 Aug 2002; Martin Schlemmer <az...@ge...> : Fix spawn_shell() and main() in sandbox.c to properly return fail status. 19 Aug 2002; Martin Schlemmer <az...@ge...> : The new canonicalize() function in libsandbox.c also resolved symlinks, which caused on cleaning sandbox errors if the symlink pointed to a file in the live root. Ripped out canonicalize() and realpath() from glibc; removed the symlink stuff, and changed them to ecanonicalize() and erealpath(). 18 Aug 2002; Martin Schlemmer <az...@ge...> : Ripped out all the wrappers, and implemented those of InstallWatch. Losts of cleanups and bugfixes. Implement a execve that forces $LIBSANDBOX in $LD_PRELOAD. We can now thus do away with the feared /etc/ld.so.preload (*g*) ... Made the needed changes to sandbox.c, sandbox.h and sandbox_futils.c. Rewrote the Makefile for most parts; it now have an install target. Reformat the whole thing to look somewhat like the reworked sandbox.c and new sandbox.h and sandbox_futils.c from: Brad House <br...@ma...>. Additional Copyrights now due to the InstallWatch code: Copyright (C) 1998-9 Pancrazio `Ezio' de Mauro <p...@de...> --- NEW FILE: Makefile --- # 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 <gb...@uw...> # # Modified 15 Apr 2002 Jon Nelson <jn...@ge...> # Clean up Makefile somewhat, and use make's implicit rules # # Modified 19 Aug 2002; Martin Schlemmer <az...@ge...> # Major rewrite to support new stuff # # $Header: /cvsroot/darwinfiles/portage/src/sandbox-1.1/Makefile,v 1.1 2002/09/08 16:21:12 jimmacr Exp $ CC = gcc LD = ld CFLAGS = OBJ_DEFINES = -D_GNU_SOURCE -DPIC -fPIC -D_REENTRANT LIBS = LDFLAGS = DESTDIR = TARGETS = libsandbox.so sandbox all: $(TARGETS) sandbox: sandbox.o sandbox_futils.o $(CC) $^ -ldl -lc -o $@ sandbox.o: sandbox.c sandbox.h $(CC) $(CFLAGS) -Wall -c sandbox.c sandbox_futils.o: sandbox_futils.c sandbox.h $(CC) $(CFLAGS) -Wall -c $(OBJ_DEFINES) sandbox_futils.c libsandbox.so: libsandbox.o sandbox_futils.o canonicalize.o $(LD) $^ -shared -fPIC -ldl -lc -o $@ libsandbox.o: libsandbox.c localdecls.h $(CC) $(CFLAGS) -Wall -c $(OBJ_DEFINES) libsandbox.c canonicalize.o: canonicalize.c $(CC) $(CFLAGS) -Wall -c $(OBJ_DEFINES) canonicalize.c localdecls.h: create-localdecls libctest.c ./create-localdecls install: all install -d -m 0755 $(DESTDIR)/lib install -d -m 0755 $(DESTDIR)/usr/lib/portage/bin install -d -m 0755 $(DESTDIR)/usr/lib/portage/lib install -m 0755 libsandbox.so $(DESTDIR)/lib install -m 0755 sandbox $(DESTDIR)/usr/lib/portage/bin install -m 0644 sandbox.bashrc $(DESTDIR)/usr/lib/portage/lib clean: rm -f $(TARGETS) rm -f *.o *~ core rm -f localdecls.h # vim:expandtab noai:cindent ai --- NEW FILE: canonicalize.c --- /* Return the canonical absolute name of a given file. Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ /* * $Header: /cvsroot/darwinfiles/portage/src/sandbox-1.1/canonicalize.c,v 1.1 2002/09/08 16:21:12 jimmacr Exp $ */ #include <stdlib.h> #include <string.h> #include <unistd.h> #include <limits.h> #include <sys/param.h> #include <sys/stat.h> #include <errno.h> #include <stddef.h> #ifndef __set_errno # define __set_errno(val) errno = (val) #endif /* Return the canonical absolute name of file NAME. A canonical name does not contain any `.', `..' components nor any repeated path separators ('/') or symlinks. All path components must exist. If RESOLVED is null, the result is malloc'd; otherwise, if the canonical name is PATH_MAX chars or more, returns null with `errno' set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars, returns the name in RESOLVED. If the name cannot be resolved and RESOLVED is non-NULL, it contains the path of the first component that cannot be resolved. If the path can be resolved, RESOLVED holds the same value as the value returned. */ /* Modified: 19 Aug 2002; Martin Schlemmer <az...@ge...> * * Cleaned up unneeded stuff, and change so that it will not * resolve symlinks. Also prepended a 'e' to functions that * I did not rip out. * */ static char * ecanonicalize (const char *name, char *resolved) { char *rpath, *dest; const char *start, *end, *rpath_limit; long int path_max; if (name == NULL) { /* As per Single Unix Specification V2 we must return an error if either parameter is a null pointer. We extend this to allow the RESOLVED parameter to be NULL in case the we are expected to allocate the room for the return value. */ __set_errno (EINVAL); return NULL; } if (name[0] == '\0') { /* As per Single Unix Specification V2 we must return an error if the name argument points to an empty string. */ __set_errno (ENOENT); return NULL; } #ifdef PATH_MAX path_max = PATH_MAX; #else path_max = pathconf (name, _PC_PATH_MAX); if (path_max <= 0) path_max = 1024; #endif rpath = resolved ? alloca (path_max) : malloc (path_max); rpath_limit = rpath + path_max; if (name[0] != '/') { if (!getcwd (rpath, path_max)) { rpath[0] = '\0'; goto error; } dest = strchr (rpath, '\0'); } else { rpath[0] = '/'; dest = rpath + 1; } for (start = end = name; *start; start = end) { /* Skip sequence of multiple path-separators. */ while (*start == '/') ++start; /* Find end of path component. */ for (end = start; *end && *end != '/'; ++end) /* Nothing. */; if (end - start == 0) break; else if (end - start == 1 && start[0] == '.') /* nothing */; else if (end - start == 2 && start[0] == '.' && start[1] == '.') { /* Back up to previous component, ignore if at root already. */ if (dest > rpath + 1) while ((--dest)[-1] != '/'); } else { size_t new_size; if (dest[-1] != '/') *dest++ = '/'; if (dest + (end - start) >= rpath_limit) { ptrdiff_t dest_offset = dest - rpath; if (resolved) { __set_errno (ENAMETOOLONG); if (dest > rpath + 1) dest--; *dest = '\0'; goto error; } new_size = rpath_limit - rpath; if (end - start + 1 > path_max) new_size += end - start + 1; else new_size += path_max; rpath = realloc (rpath, new_size); rpath_limit = rpath + new_size; if (rpath == NULL) return NULL; dest = rpath + dest_offset; } dest = __mempcpy (dest, start, end - start); *dest = '\0'; } } #if 0 if (dest > rpath + 1 && dest[-1] == '/') --dest; #endif *dest = '\0'; return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath; error: if (resolved) strcpy (resolved, rpath); else free (rpath); return NULL; } char * erealpath (const char *name, char *resolved) { if (resolved == NULL) { __set_errno (EINVAL); return NULL; } return ecanonicalize (name, resolved); } // vim:expandtab noai:cindent ai --- NEW FILE: create-localdecls --- #!/bin/sh # This is a quick'n'dirty hack to make the program behave correctly # under different systems. # Example: # when using libc5, (f)trucate's offset argument type is size_t with # libc5, but it's off_t with libc6 (glibc2). # # Uhm... time to learn GNU autoconf :-) # # $Header: /cvsroot/darwinfiles/portage/src/sandbox-1.1/create-localdecls,v 1.1 2002/09/08 16:21:12 jimmacr Exp $ OUTFILE='localdecls.h' echo '/* This file is automatically generated *' > $OUTFILE echo ' * Modify create-localdecls instead of this */' >> $OUTFILE echo >> $OUTFILE echo '#ifndef __LOCALDECLS_H_' > $OUTFILE echo '#define __LOCALDECLS_H_' >> $OUTFILE echo >> $OUTFILE ### ### ### echo -n 'Checking truncate argument type... ' if grep -q 'truncate.*size_t' /usr/include/unistd.h ; then echo 'size_t' echo '#define TRUNCATE_T size_t' >> $OUTFILE else echo 'off_t' # At least, I HOPE it's off_t :-) echo '#define TRUNCATE_T off_t' >> $OUTFILE fi ### ### ### echo -n 'Checking libc version... ' gcc -Wall -o libctest libctest.c VERSION=`ldd libctest | grep libc\\.so | awk '{print $1}'` rm libctest echo $VERSION echo "#define LIBC_VERSION \"$VERSION\"" >> $OUTFILE if test "$VERSION" = 'libc.so.5' ; then echo '#define BROKEN_RTLD_NEXT' >> $OUTFILE echo '#define LIBC 5' >> $OUTFILE fi if test "$VERSION" = 'libc.so.6' ; then echo -n 'Checking glibc subversion... ' tmp="`ldd /bin/sh | grep libc.so 2> /dev/null`" LibcPath=`expr "$tmp" : '[^/]*\(/[^ ]*\)'` tmp="`strings $LibcPath | grep -i 'c library'`" OsLibcMajor=`expr "$tmp" : '.* \([0-9][0-9]*\)'` OsLibcMinor=`expr "$tmp" : '.* [0-9][0-9]*\.\([0-9][0-9]*\)'` case "$OsLibcMajor" in 2) # 2 is the glibc version case "$OsLibcMinor" in 0) echo '#define GLIBC_MINOR 0' >> $OUTFILE SUBVERSION='glibc-2.0' ;; 1) echo '#define GLIBC_MINOR 1' >> $OUTFILE SUBVERSION='glibc-2.1' ;; 2) echo '#define GLIBC_MINOR 2' >> $OUTFILE SUBVERSION='glibc-2.2' ;; *) echo 'Treated as glibc >= 2.1 (finger crossed)' echo '#define GLIBC_MINOR 1' >> $OUTFILE SUBVERSION='glibc-2.1' ;; esac ;; esac fi echo >> $OUTFILE echo '#endif' >> $OUTFILE echo --- NEW FILE: libctest.c --- /* Dummy program to check your libc version */ int main(void) { return 0; } --- NEW FILE: libsandbox.c --- /* S * 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 <gb...@uw...> * * Post Bevin leaving Gentoo ranks: * -------------------------------- * Ripped out all the wrappers, and implemented those of InstallWatch. * Losts of cleanups and bugfixes. Implement a execve that forces $LIBSANDBOX * in $LD_PRELOAD. Reformat the whole thing to look somewhat like the reworked [...1145 lines suppressed...] static int before_syscall_open_int(const char* func, const char* file, int flags) { if ((flags & O_WRONLY) || (flags & O_RDWR)) { return before_syscall("open_wr", file); } else { return before_syscall("open_rd", file); } } static int before_syscall_open_char(const char* func, const char* file, const char* mode) { if ((strcmp(mode, "r") == 0) || (strcmp(mode, "rb") == 0)) { return before_syscall("open_rd", file); } else { return before_syscall("open_wr", file); } } // vim:expandtab noai:cindent ai --- NEW FILE: sandbox.bashrc --- # 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 <gb...@uw...> # $Header: /cvsroot/darwinfiles/portage/src/sandbox-1.1/sandbox.bashrc,v 1.1 2002/09/08 16:21:12 jimmacr 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'" --- NEW FILE: sandbox.c --- /* ** 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 <gb...@uw...> ** $Header: /cvsroot/darwinfiles/portage/src/sandbox-1.1/sandbox.c,v 1.1 2002/09/08 16:21:12 jimmacr 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> #include <fcntl.h> #include "sandbox.h" int preload_adaptable = 1; int cleaned_up = 0; int print_debug = 0; /* Read pids file, and load active pids into an array. Return number of pids in array */ int load_active_pids(int fd, int **pids) { char *data = NULL; char *ptr = NULL, *ptr2 = NULL; int my_pid; int num_pids = 0; long len; pids[0] = NULL; len = file_length(fd); /* Allocate and zero datablock to read pids file */ data = (char *)malloc((len + 1)*sizeof(char)); memset(data, 0, len + 1); /* Start at beginning of file */ lseek(fd, 0L, SEEK_SET); /* read entire file into a buffer */ read(fd, data, len); ptr = data; /* Loop and read all pids */ while (1) { /* Find new line */ ptr2 = strchr(ptr, '\n'); if (ptr2 == NULL) break; /* No more PIDs */ /* clear the \n. And ptr should have a null-terminated decimal string */ ptr2[0] = 0; my_pid = atoi(ptr); /* If the PID is still alive, add it to our array */ if ((0 != my_pid) && (0 == kill(my_pid, 0))) { pids[0] = (int *)realloc(pids[0], (num_pids + 1)*sizeof(int)); pids[0][num_pids] = my_pid; num_pids++; } /* Put ptr past the NULL we just wrote */ ptr = ptr2 + 1; } if (data) free(data); return num_pids; } /* Read ld.so.preload file, and loads dirs into an array. Return number of entries in array */ int load_preload_libs(int fd, char ***preloads) { char *data = NULL; char *ptr = NULL, *ptr2 = NULL; int num_entries = 0; long len; preloads[0] = NULL; len = file_length(fd); /* Allocate and zero datablock to read pids file */ data = (char *)malloc((len + 1)*sizeof(char)); memset(data, 0, len + 1); /* Start at beginning of file */ lseek(fd, 0L, SEEK_SET); /* read entire file into a buffer */ read(fd, data, len); ptr = data; /* Loop and read all pids */ while (1) { /* Find new line */ ptr2 = strchr(ptr, '\n'); /* clear the \n. And ptr should have a null-terminated decimal string * Don't break from the loop though because the last line may not * terminated with a \n */ if (NULL != ptr2) ptr2[0] = 0; /* If listing does not match our libname, add it to the array */ if ((strlen(ptr)) && (NULL == strstr(ptr, LIB_NAME))) { preloads[0] = (char **)realloc(preloads[0], (num_entries + 1)*sizeof(char **)); preloads[0][num_entries] = strdup(ptr); num_entries++; } if (NULL == ptr2) break; /* No more PIDs */ /* Put ptr past the NULL we just wrote */ ptr = ptr2 + 1; } if (data) free(data); return num_entries; } void cleanup() { int i = 0; int success = 1; int pids_file = -1, num_of_pids = 0; int *pids_array = NULL; char pid_string[255]; #ifdef USE_LD_SO_PRELOAD int preload_file = -1, num_of_preloads = 0; char preload_entry[255]; char **preload_array = NULL; #endif /* 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 (print_debug) printf("Cleaning up pids file.\n"); /* Stat the PIDs file, make sure it exists and is a regular file */ if (file_exist(PIDS_FILE, 1) <= 0) { perror(">>> pids file is not a regular file"); success = 0; /* We should really not fail if the pidsfile is missing here, but * rather just exit cleanly, as there is still some cleanup to do */ return; } pids_file = file_open(PIDS_FILE, "r+", 0); if (-1 == pids_file) { success = 0; /* Nothing more to do here */ return; } /* Load "still active" pids into an array */ num_of_pids = load_active_pids(pids_file, &pids_array); //printf("pids: %d\r\n", num_of_pids); #ifdef USE_LD_SO_PRELOAD /* clean the /etc/ld.so.preload file if no other sandbox * processes are running anymore */ if (1 == num_of_pids) { success = 1; if (print_debug) printf("Cleaning up /etc/ld.so.preload.\n"); preload_file = file_open("/etc/ld.so.preload", "r+", 0); if (-1 != preload_file) { /* Load all the preload libraries into an array */ num_of_preloads = load_preload_libs(preload_file, &preload_array); //printf("num preloads: %d\r\n", num_of_preloads); /* Clear file */ file_truncate(preload_file); /* 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; } } } /* Free memory used to store preload array */ for (i = 0; i < num_of_preloads; i++) { if (preload_array[i]) free(preload_array[i]); preload_array[i] = NULL; } if (preload_array) free(preload_array); preload_array = NULL; file_close(preload_file); preload_file = -1; } } #endif file_truncate(pids_file); /* 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; } } file_close(pids_file); pids_file = -1; } else { file_close(pids_file); pids_file = -1; /* remove the pidsfile, as this was the last sandbox */ unlink(PIDS_FILE); } if (pids_array != NULL) { free(pids_array); pids_array = NULL; } } if (0 == success) { return; } } void stop(int signum) { printf("Caught signal %d\r\n", signum); cleanup(); } void setenv_sandbox_write(char *home_dir, char *portage_tmp_dir, char *var_tmp_dir, char *tmp_dir) { char sandbox_write_var[1024]; if (!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/"); /* How the heck is this possible?? we just set it above! */ } 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/"); /* Still don't think this is possible, am I just stupid or something? */ } 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/"); /* Amazing, one I think is possible */ } 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); } } void setenv_sandbox_predict(char *home_dir) { char sandbox_predict_var[1024]; if (!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); } } int print_sandbox_log(char *sandbox_log) { int sandbox_log_file = -1; char *beep_count_env = NULL; int i, beep_count = 0; long len = 0; char *buffer = NULL; sandbox_log_file=file_open(sandbox_log, "r", 0); if (-1 == sandbox_log_file) { return 0; } len = file_length(sandbox_log_file); buffer = (char *)malloc((len + 1)*sizeof(char)); memset(buffer, 0, len + 1); read(sandbox_log_file, buffer, len); file_close(sandbox_log_file); printf("\e[31;01m--------------------------- ACCESS VIOLATION SUMMARY ---------------------------\033[0m\n"); printf("\e[31;01mLOG FILE = \"%s\"\033[0m\n", sandbox_log); printf("\n"); printf("%s", buffer); if (buffer) free(buffer); buffer = NULL; printf("\e[31;01m--------------------------------------------------------------------------------\033[0m\n"); 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); } } return 1; } int spawn_shell(char *argv_bash[]) { #ifdef USE_SYSTEM_SHELL int i = 0; char *sh = NULL; int first = 1; int ret; long len = 0; while (1) { if (NULL == argv_bash[i]) break; if (NULL != sh) len = strlen(sh); sh = (char *)realloc(sh, len+strlen(argv_bash[i]) + 5); if (first) { sh[0] = 0; first = 0; } strcat(sh, "\""); strcat(sh, argv_bash[i]); strcat(sh, "\" "); //printf("%s\n", argv_bash[i]); i++; } printf("%s\n", sh); ret = system(sh); if (sh) free(sh); sh = NULL; if (-1 == ret) return 0; return 1; #else # ifndef NO_FORK int pid; int status = 0; int ret = 0; pid = fork(); /* Child's process */ if (0 == pid) { # endif execv(argv_bash[0], argv_bash); # ifndef NO_FORK return 0; } else if (pid < 0) { return 0; } ret = waitpid(pid, &status, 0); if ((-1 == ret) || (status > 0)) return 0; # endif return 1; #endif } int main(int argc, char** argv) { int i = 0, success = 1; int preload_file = -1; int sandbox_log_presence = 0; int sandbox_log_file = -1; int pids_file = -1; long len; int *pids_array = NULL; int num_of_pids = 0; // char run_arg[255]; char portage_tmp_dir[PATH_MAX]; char var_tmp_dir[PATH_MAX]; char tmp_dir[PATH_MAX]; char sandbox_log[255]; char sandbox_debug_log[255]; char sandbox_dir[255]; char sandbox_lib[255]; char sandbox_rc[255]; char pid_string[255]; char **argv_bash = NULL; char *run_str = "-c"; char *home_dir = NULL; char *tmp_string = NULL; #ifdef USE_LD_SO_PRELOAD char **preload_array = NULL; int num_of_preloads = 0; #endif /* Only print info if called with no arguments .... */ if (argc < 2) { print_debug = 1; } if (print_debug) 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 { /* determine the location of all the sandbox support files */ if (print_debug) printf("Detection of the support files.\n"); /* Generate base sandbox path */ tmp_string = get_sandbox_path(argv[0]); strncpy(sandbox_dir, tmp_string, 254); if (tmp_string) free(tmp_string); tmp_string = NULL; strcat(sandbox_dir, "/"); /* Generate sandbox lib path */ tmp_string = get_sandbox_lib(sandbox_dir); strncpy(sandbox_lib, tmp_string, 254); if (tmp_string) free(tmp_string); tmp_string = NULL; /* Generate sandbox bashrc path */ tmp_string = get_sandbox_rc(sandbox_dir); strncpy(sandbox_rc, tmp_string, 254); if (tmp_string) free(tmp_string); tmp_string = NULL; /* verify the existance of required files */ if (print_debug) printf("Verification of the required files.\n"); if (file_exist(sandbox_lib, 0) <= 0) { fprintf(stderr, "Could not open the sandbox library at '%s'.\n", sandbox_lib); return -1; } else if (file_exist(sandbox_rc, 0) <= 0) { fprintf(stderr, "Could not open the sandbox rc file at '%s'.\n", sandbox_rc); return -1; } #ifdef USE_LD_SO_PRELOAD /* ensure that the /etc/ld.so.preload file contains an entry for the sandbox lib */ if (print_debug) printf("Setting up the ld.so.preload file.\n"); #endif /* check if the /etc/ld.so.preload is a regular file */ if (file_exist("/etc/ld.so.preload", 1) < 0) { fprintf(stderr, ">>> /etc/ld.so.preload file is not a regular file\n"); exit(1); } /* Our r+ also will create the file if it doesn't exist */ preload_file=file_open("/etc/ld.so.preload", "r+", 1, 0644); if (-1 == preload_file) { preload_adaptable = 0; /* exit(1);*/ } #ifdef USE_LD_SO_PRELOAD /* Load entries of preload table */ num_of_preloads = load_preload_libs(preload_file, &preload_array); /* Zero out our ld.so.preload file */ file_truncate(preload_file); /* Write contents of preload file */ for (i = 0; i < num_of_preloads + 1; i++) { /* First entry should be our sandbox library */ if (0 == i) { if (write(preload_file, sandbox_lib, strlen(sandbox_lib)) != strlen(sandbox_lib)) { perror(">>> /etc/ld.so.preload file write"); success = 0; break; } } else { /* Output all other preload entries */ if (write(preload_file, preload_array[i - 1], strlen(preload_array[i - 1])) != strlen(preload_array[i - 1])) { perror(">>> /etc/ld.so.preload file write"); success = 0; break; } } /* Don't forget the return character after each line! */ if (1 != write(preload_file, "\n", 1)) { perror(">>> /etc/ld.so.preload file write"); success = 0; break; } } for (i = 0; i < num_of_preloads; i++) { if (preload_array[i]) free(preload_array[i]); preload_array[i] = NULL; } if (preload_array) free(preload_array); num_of_preloads = 0; preload_array = NULL; #endif /* That's all we needed to do with the preload file */ file_close(preload_file); preload_file = -1; /* set up the required environment variables */ if (print_debug) printf("Setting up the required environment variables.\n"); /* Generate sandbox log full path */ tmp_string=get_sandbox_log(); strncpy(sandbox_log, tmp_string, 254); if (tmp_string) free(tmp_string); tmp_string = NULL; setenv(ENV_SANDBOX_LOG, sandbox_log, 1); snprintf(sandbox_debug_log, 254, "%s%s%s", DEBUG_LOG_FILE_PREFIX, pid_string, 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 (!getenv(ENV_SANDBOX_DENY)) { setenv(ENV_SANDBOX_DENY, LD_PRELOAD_FILE, 1); } if (!getenv(ENV_SANDBOX_READ)) { setenv(ENV_SANDBOX_READ, "/", 1); } /* Set up Sandbox Write path */ setenv_sandbox_write(home_dir, portage_tmp_dir, var_tmp_dir, tmp_dir); setenv_sandbox_predict(home_dir); 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); } argv_bash=(char **)malloc(6 * sizeof(char *)); argv_bash[0] = strdup("/bin/bash"); argv_bash[1] = strdup("-rcfile"); argv_bash[2] = strdup(sandbox_rc); if (argc < 2) { argv_bash[3] = NULL; } else { argv_bash[3] = strdup(run_str); /* "-c" */ } argv_bash[4] = NULL; /* strdup(run_arg); */ argv_bash[5] = NULL; if (argc >= 2) { for (i = 1; i< argc; i++) { if (NULL == argv_bash[4]) len = 0; else len = strlen(argv_bash[4]); argv_bash[4]=(char *)realloc(argv_bash[4], (len + strlen(argv[i]) + 2) * sizeof(char)); if (0 == len) argv_bash[4][0] = 0; if (1 != i) strcat(argv_bash[4], " "); strcat(argv_bash[4], argv[i]); } } #if 0 char* argv_bash[] = { "/bin/bash", "-rcfile", NULL, NULL, NULL, NULL }; /* 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]); } } #endif /* 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); /* Load our PID into PIDs file if environment is adaptable */ if (preload_adaptable) { success = 1; if (file_exist(PIDS_FILE, 1) < 0) { success = 0; fprintf(stderr, ">>> pids file is not a regular file"); } else { pids_file=file_open(PIDS_FILE, "r+", 1, 0644); if (-1 == pids_file) { success = 0; } else { /* Grab still active pids */ num_of_pids = load_active_pids(pids_file, &pids_array); /* Zero out file */ file_truncate(pids_file); /* Output active pids, and append our pid */ for (i = 0; i < num_of_pids + 1; i++) { /* Time for our entry */ if (i == num_of_pids) { sprintf(pid_string, "%d\n", getpid()); } else { sprintf(pid_string, "%d\n", pids_array[i]); } if (write(pids_file, pid_string, strlen(pid_string)) != strlen(pid_string)) { perror(">>> /etc/ld.so.preload file write"); success = 0; break; } } /* Clean pids_array */ if (pids_array) free(pids_array); pids_array = NULL; num_of_pids = 0; /* We're done with the pids file */ file_close(pids_file); } } /* Something went wrong, bail out */ if (success == 0) exit(1); } /* STARTING PROTECTED ENVIRONMENT */ if (print_debug) { printf("The protected environment has been started.\n"); printf("--------------------------------------------------------------------------------\n"); } if (print_debug) printf("Shell being started in forked process.\n"); /* Start Bash */ if (!spawn_shell(argv_bash)) { if (print_debug) fprintf(stderr, ">>> shell process failed to spawn\n"); success = 0; } /* Free bash stuff */ for (i = 0; i < 6; i++) { if (argv_bash[i]) free(argv_bash[i]); argv_bash[i] = NULL; } if (argv_bash) free(argv_bash); argv_bash = NULL; if (print_debug) { printf("Cleaning up sandbox process\n"); } cleanup(); if (print_debug) { printf("========================== Gentoo linux path sandbox ===========================\n"); printf("The protected environment has been shut down.\n"); } if (file_exist(sandbox_log, 0)) { sandbox_log_presence = 1; success = 1; if (!print_sandbox_log(sandbox_log)) { success = 0; } #if 0 if (!success) { exit(1); } #endif sandbox_log_file = -1; } else if (print_debug) { printf("--------------------------------------------------------------------------------\n"); } if ((sandbox_log_presence) || (!success)) { return 1; } else { return 0; } } } // vim:expandtab noai:cindent ai --- NEW FILE: sandbox.h --- /* * Copyright (C) 2002 Brad House <br...@ma...>, * Possibly based on code from Geert Bevin, Uwyn, http://www.uwyn.com * Distributed under the terms of the GNU General Public License, v2 or later * Author: Brad House <br...@ma...> * * $Header: /cvsroot/darwinfiles/portage/src/sandbox-1.1/sandbox.h,v 1.1 2002/09/08 16:21:12 jimmacr Exp $ */ #ifndef __SANDBOX_H__ #define __SANDBOX_H__ /* Uncomment below to use flock instead of fcntl (POSIX way) to lock/unlock files */ /* #define USE_FLOCK */ /* Uncomment below to use system() to execute the shell rather than execv */ /* #define USE_SYSTEM_SHELL */ /* Uncomment below to use /etc/ld.so.preload (could be very intrusive!!) */ /* #define USE_LD_SO_PRELOAD */ /* Uncommend to not have the protected shell forked, just run in parent process */ /* ONLY FOR DEBUGGING PURPOSES!! (strace needs it like that) */ /* #define NO_FORK */ #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 char *get_sandbox_path(char *argv0); char *get_sandbox_lib(char *sb_path); char *get_sandbox_rc(char *sb_path); char *get_sandbox_log(); char *dirname(const char *path); int file_getmode(char *mode); long file_tell(int fp); int file_lock(int fd, int lock, char *filename); int file_unlock(int fd); int file_locktype(char *mode); int file_open(char *filename, char *mode, int perm_specified, ...); void file_close(int fd); long file_length(int fd); int file_truncate(int fd); int file_exist(char *filename, int checkmode); #endif // vim:expandtab noai:cindent ai --- NEW FILE: sandbox_futils.c --- /* * Copyright (C) 2002 Brad House <br...@ma...> * Distributed under the terms of the GNU General Public License, v2 or later * Author: Brad House <br...@ma...> * * $Header: /cvsroot/darwinfiles/portage/src/sandbox-1.1/sandbox_futils.c,v 1.1 2002/09/08 16:21:12 jimmacr Exp $ * */ #include <errno.h> #include <fcntl.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h> #include <stdarg.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> #include <fcntl.h> #include "sandbox.h" char *get_sandbox_path(char *argv0) { char path[255]; char *cwd = NULL; /* ARGV[0] specifies full path */ if (argv0[0] == '/') { strncpy(path, argv0, 254); /* ARGV[0] specifies relative path */ } else { getcwd(cwd, 253); sprintf(path, "%s/%s", cwd, argv0); if (cwd) free(cwd); cwd = NULL; } /* Return just directory */ return(dirname(path)); } char *get_sandbox_lib(char *sb_path) { char path[255]; snprintf(path, 254, "/lib/%s", LIB_NAME); if (file_exist(path, 0) <= 0) { snprintf(path, 254, "%s%s", sb_path, LIB_NAME); } return(strdup(path)); } char *get_sandbox_rc(char *sb_path) { char path[255]; snprintf(path, 254, "/usr/lib/portage/lib/%s", BASHRC_NAME); if (file_exist(path, 0) <= 0) { snprintf(path, 254, "%s%s", sb_path, BASHRC_NAME); } return(strdup(path)); } char *get_sandbox_log() { char path[255]; char pid_string[20]; char *sandbox_log_env = NULL; sprintf(pid_string, "%d", getpid()); strcpy(path, LOG_FILE_PREFIX); sandbox_log_env = getenv(ENV_SANDBOX_LOG); if (sandbox_log_env) { strcat(path, sandbox_log_env); strcat(path, "-"); } strcat(path, pid_string); strcat(path, LOG_FILE_EXT); return(strdup(path)); } /* Obtain base directory name. Do not allow trailing / */ char *dirname(const char *path) { char *ret = NULL; char *ptr = NULL; int loc = 0, i; int cut_len = 0; /* don't think NULL will ever be passed, but just in case */ if (NULL == path) return(strdup(".")); /* Grab pointer to last slash */ ptr = strrchr(path, '/'); if (NULL == ptr) { return(strdup(".")); } /* decimal location of pointer */ loc = strlen(path)-strlen(ptr); /* Remove any trailing slash */ for (i = loc-1; i >= 0; i--) { if (path[i] != '/') { cut_len = i; break; } } /* It could have been just a plain /, return a 1byte 0 filled string */ if (0 == cut_len) return(strdup("")); /* Allocate memory, and return the directory */ ret = (char *)malloc((cut_len + 1) * sizeof(char)); memcpy(ret, path, cut_len); ret[cut_len] = 0; return(ret); } /* 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; }*/ /* Convert text (string) modes to integer values */ int file_getmode(char *mode) { int mde = 0; if (0 == strcasecmp(mode, "r+")) { mde = O_RDWR | O_CREAT; } else if (0 == strcasecmp(mode, "w+")) { mde = O_RDWR | O_CREAT | O_TRUNC; } else if (0 == strcasecmp(mode, "a+")) { mde = O_RDWR | O_CREAT | O_APPEND; } else if (0 == strcasecmp(mode, "r")) { mde = O_RDONLY; } else if (0 == strcasecmp(mode, "w")) { mde = O_WRONLY | O_CREAT | O_TRUNC; } else if (0 == strcasecmp(mode, "a")) { mde = O_WRONLY | O_APPEND | O_CREAT; } else { mde = O_RDONLY; } return(mde); } /* Get current position in file */ long file_tell(int fp) { return(lseek(fp, 0L, SEEK_CUR)); } /* lock the file, preferrably the POSIX way */ int file_lock(int fd, int lock, char *filename) { int err; #ifdef USE_FLOCK if (flock(fd, lock) < 0) { err = errno; fprintf(stderr, ">>> %s flock file lock: %s\n", filename, strerror(err)); return 0; } #else struct flock fl; fl.l_type = lock; fl.l_whence = SEEK_SET; fl.l_start = 0L; fl.l_len = 0L; fl.l_pid = getpid(); if (fcntl(fd, F_SETLKW, &fl) < 0) { err = errno; fprintf(stderr, ">>> %s fcntl file lock: %s\n", filename, strerror(err)); return 0; } #endif return 1; } /* unlock the file, preferrably the POSIX way */ int file_unlock(int fd) { #ifdef USE_FLOCK if (flock(fd, LOCK_UN) < 0) { perror(">>> flock file unlock"); return 0; } #else struct flock fl; fl.l_type = F_UNLCK; fl.l_whence = SEEK_SET; fl.l_start = 0L; fl.l_len = 0L; fl.l_pid = getpid(); if (fcntl(fd, F_SETLKW, &fl) < 0) { perror(">>> fcntl file unlock"); return 0; } #endif return 1; } /* Auto-determine from how the file was opened, what kind of lock to lock * the file with */ int file_locktype(char *mode) { #ifdef USE_FLOCK if (NULL != (strchr(mode, 'w')) || (NULL != strchr(mode, '+')) || (NULL != strchr(mode, 'a'))) return(LOCK_EX); return(LOCK_SH); #else if (NULL != (strchr(mode, 'w')) || (NULL != strchr(mode, '+')) || (NULL != strchr(mode, 'a'))) return(F_WRLCK); return(F_RDLCK); #endif } /* Use standard fopen style modes to open the specified file. Also auto-determines and * locks the file either in shared or exclusive mode depending on opening mode */ int file_open(char *filename, char *mode, int perm_specified, ...) { int fd; char error[250]; va_list ap; int perm; if (perm_specified) { va_start(ap, perm_specified); perm = va_arg(ap, int); va_end(ap); } if (perm_specified) { fd = open(filename, file_getmode(mode), perm); } else { fd = open(filename, file_getmode(mode)); } if (-1 == fd) { snprintf(error, 249, ">>> %s file mode: %s open", filename, mode); perror(error); return(fd); } /* Only lock the file if opening succeeded */ if (-1 != fd) { if (0 == file_lock(fd, file_locktype(mode), filename)) { close(fd); return -1; } } else { snprintf(error, 249, ">>> %s file mode:%s open", filename, mode); perror(error); } return(fd); } /* Close and unlock file */ void file_close(int fd) { if (-1 != fd) { file_unlock(fd); close(fd); } } /* Return length of file */ long file_length(int fd) { long pos, len; pos = file_tell(fd); len = lseek(fd, 0L, SEEK_END); lseek(fd, pos, SEEK_SET); return(len); } /* Zero out file */ int file_truncate(int fd) { lseek(fd, 0L, SEEK_SET); if (ftruncate(fd, 0) < 0) { perror(">>> file truncate"); return 0; } return 1; } /* Check to see if a file exists Return: 1 success, 0 file not found, -1 error */ int file_exist(char *filename, int checkmode) { struct stat mystat; /* Verify file exists and is regular file (not sym link) */ if (checkmode) { if (-1 == lstat(filename, &mystat)) { /* file doesn't exist */ if (ENOENT == errno) { return 0; } else { /* permission denied or other error */ perror(">>> stat file"); return -1; } } if (!S_ISREG(mystat.st_mode)) return -1; /* Just plain verify the file exists */ } else { if (-1 == stat(filename, &mystat)) { /* file does not exist */ if (ENOENT == errno) { return 0; } else { /* permission denied or other error */ perror(">>> stat file"); return -1; } } } return 1; } // vim:expandtab noai:cindent ai |