2 ** Path sandbox for the gentoo linux portage package system, initially
3 ** based on the ROCK Linux Wrapper for getting a list of created files
5 ** to integrate with bash, bash should have been built like this
7 ** ./configure --prefix=<prefix> --host=<host> --without-gnu-malloc
9 ** it's very important that the --enable-static-link option is NOT specified
11 ** Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
12 ** Distributed under the terms of the GNU General Public License, v2 or later
13 ** Author : Geert Bevin <gbevin@uwyn.com>
14 ** $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-1.1/Attic/sandbox.c,v 1.20.2.1 2004/12/01 22:14:09 carpaski Exp $
17 /* #define _GNU_SOURCE */
29 #include <sys/types.h>
30 #include <sys/resource.h>
36 int preload_adaptable = 1;
41 /* Read pids file, and load active pids into an array. Return number of pids in array */
43 load_active_pids(int fd, int **pids)
46 char *ptr = NULL, *ptr2 = NULL;
53 len = file_length(fd);
55 /* Allocate and zero datablock to read pids file */
56 data = (char *) malloc((len + 1) * sizeof (char));
57 memset(data, 0, len + 1);
59 /* Start at beginning of file */
60 lseek(fd, 0L, SEEK_SET);
62 /* read entire file into a buffer */
67 /* Loop and read all pids */
70 ptr2 = strchr(ptr, '\n');
72 break; /* No more PIDs */
74 /* Clear the \n. And ptr should have a null-terminated decimal string */
79 /* If the PID is still alive, add it to our array */
80 if ((0 != my_pid) && (0 == kill(my_pid, 0))) {
81 pids[0] = (int *) realloc(pids[0], (num_pids + 1) * sizeof (int));
82 pids[0][num_pids] = my_pid;
86 /* Put ptr past the NULL we just wrote */
97 /* Read ld.so.preload file, and loads dirs into an array. Return number of entries in array */
99 load_preload_libs(int fd, char ***preloads)
102 char *ptr = NULL, *ptr2 = NULL;
108 len = file_length(fd);
110 /* Allocate and zero datablock to read pids file */
111 data = (char *) malloc((len + 1) * sizeof (char));
112 memset(data, 0, len + 1);
114 /* Start at beginning of file */
115 lseek(fd, 0L, SEEK_SET);
117 /* read entire file into a buffer */
122 /* Loop and read all pids */
125 ptr2 = strchr(ptr, '\n');
127 /* Clear the \n. And ptr should have a null-terminated decimal string
128 * Don't break from the loop though because the last line may not
129 * terminated with a \n
134 /* If listing does not match our libname, add it to the array */
135 if ((strlen(ptr)) && (NULL == strstr(ptr, LIB_NAME))) {
137 (char **) realloc(preloads[0], (num_entries + 1) * sizeof (char **));
138 preloads[0][num_entries] = strdup(ptr);
143 break; /* No more PIDs */
145 /* Put ptr past the NULL we just wrote */
161 int pids_file = -1, num_of_pids = 0;
162 int *pids_array = NULL;
163 char pid_string[255];
164 char *sandbox_pids_file;
165 #ifdef USE_LD_SO_PRELOAD
166 int preload_file = -1, num_of_preloads = 0;
167 char preload_entry[255];
168 char **preload_array = NULL;
171 /* Generate sandbox pids-file path */
172 sandbox_pids_file = get_sandbox_pids_file();
174 /* Remove this sandbox's bash pid from the global pids
175 * file if it has rights to adapt the ld.so.preload file */
176 if ((1 == preload_adaptable) && (0 == cleaned_up)) {
181 printf("Cleaning up pids file.\n");
183 /* Stat the PIDs file, make sure it exists and is a regular file */
184 if (file_exist(sandbox_pids_file, 1) <= 0) {
185 fprintf(stderr, ">>> pids file is not a regular file");
187 /* We should really not fail if the pidsfile is missing here, but
188 * rather just exit cleanly, as there is still some cleanup to do */
192 pids_file = file_open(sandbox_pids_file, "r+", 1, 0664, "portage");
193 if (-1 == pids_file) {
195 /* Nothing more to do here */
199 /* Load "still active" pids into an array */
200 num_of_pids = load_active_pids(pids_file, &pids_array);
201 //printf("pids: %d\r\n", num_of_pids);
203 #ifdef USE_LD_SO_PRELOAD
204 /* clean the /etc/ld.so.preload file if no other sandbox
205 * processes are running anymore */
206 if (1 == num_of_pids) {
210 printf("Cleaning up /etc/ld.so.preload.\n");
212 preload_file = file_open("/etc/ld.so.preload", "r+", 1, 0644);
213 if (-1 != preload_file) {
214 /* Load all the preload libraries into an array */
215 num_of_preloads = load_preload_libs(preload_file, &preload_array);
216 //printf("num preloads: %d\r\n", num_of_preloads);
218 file_truncate(preload_file);
220 /* store the other preload libraries back into the /etc/ld.so.preload file */
221 if (num_of_preloads > 0) {
222 for (i = 0; i < num_of_preloads; i++) {
223 sprintf(preload_entry, "%s\n", preload_array[i]);
227 strlen(preload_entry)) != strlen(preload_entry)) {
228 perror(">>> /etc/ld.so.preload file write");
235 /* Free memory used to store preload array */
236 for (i = 0; i < num_of_preloads; i++) {
237 if (preload_array[i])
238 free(preload_array[i]);
239 preload_array[i] = NULL;
243 preload_array = NULL;
245 file_close(preload_file);
251 file_truncate(pids_file);
253 /* if pids are still running, write only the running pids back to the file */
254 if (num_of_pids > 1) {
255 for (i = 0; i < num_of_pids; i++) {
256 if (pids_array[i] != getpid()) {
257 sprintf(pid_string, "%d\n", pids_array[i]);
259 if (write(pids_file, pid_string, strlen(pid_string)) !=
260 strlen(pid_string)) {
261 perror(">>> pids file write");
268 file_close(pids_file);
272 file_close(pids_file);
275 /* remove the pidsfile, as this was the last sandbox */
276 unlink(sandbox_pids_file);
279 if (pids_array != NULL)
284 free(sandbox_pids_file);
292 if (stop_called == 0) {
294 printf("Caught signal %d in pid %d\r\n", signum, getpid());
297 fprintf(stderr, "Pid %d alreadly caught signal and is still cleaning up\n", getpid());
302 setenv_sandbox_write(char *home_dir, char *portage_tmp_dir, char *var_tmp_dir,
307 /* bzero out entire buffer then append trailing 0 */
308 memset(buf, 0, sizeof(buf));
310 if (!getenv(ENV_SANDBOX_WRITE)) {
311 /* these could go into make.globals later on */
312 snprintf(buf, sizeof(buf),
313 "%s:%s/.gconfd/lock:%s/.bash_history:", \
314 "/dev/zero:/dev/fd/:/dev/null:/dev/pts/:" \
315 "/dev/vc/:/dev/tty:/tmp/:" \
316 "/dev/shm/ngpt:/var/log/scrollkeeper.log:" \
317 "/usr/tmp/conftest:/usr/lib/conftest:" \
318 "/usr/lib32/conftest:/usr/lib64/conftest:" \
319 "/usr/tmp/cf:/usr/lib/cf:/usr/lib32/cf:/usr/lib64/cf",
322 if (NULL == portage_tmp_dir) {
323 strncat(buf, tmp_dir, sizeof(buf));
324 strncat(buf, ":", sizeof(buf));
325 strncat(buf, var_tmp_dir, sizeof(buf));
326 strncat(buf, ":/tmp/:/var/tmp/", sizeof(buf));
328 strncat(buf, portage_tmp_dir, sizeof(buf));
329 strncat(buf, ":", sizeof(buf));
330 strncat(buf, tmp_dir, sizeof(buf));
331 strncat(buf, ":", sizeof(buf));
332 strncat(buf, var_tmp_dir, sizeof(buf));
333 strncat(buf, ":/tmp/:/var/tmp/", sizeof(buf));
335 buf[sizeof(buf) - 1] = '\0';
336 setenv(ENV_SANDBOX_WRITE, buf, 1);
341 setenv_sandbox_predict(char *home_dir)
345 memset(buf, 0, sizeof(buf));
347 if (!getenv(ENV_SANDBOX_PREDICT)) {
348 /* these should go into make.globals later on */
349 snprintf(buf, sizeof(buf), "%s/.:" \
350 "/usr/lib/python2.0/:" \
351 "/usr/lib/python2.1/:" \
352 "/usr/lib/python2.2/:" \
353 "/usr/lib/python2.3/:" \
354 "/usr/lib/python2.4/:" \
355 "/usr/lib/python2.5/:" \
356 "/usr/lib/python3.0/:",
359 buf[sizeof(buf) - 1] = '\0';
360 setenv(ENV_SANDBOX_PREDICT, buf, 1);
365 print_sandbox_log(char *sandbox_log)
367 int sandbox_log_file = -1;
368 char *beep_count_env = NULL;
369 int i, color, beep_count = 0;
373 sandbox_log_file = file_open(sandbox_log, "r", 1, 0664, "portage");
374 if (-1 == sandbox_log_file)
377 len = file_length(sandbox_log_file);
378 buffer = (char *) malloc((len + 1) * sizeof (char));
379 memset(buffer, 0, len + 1);
380 read(sandbox_log_file, buffer, len);
381 file_close(sandbox_log_file);
383 color = ( (getenv("NOCOLOR") != NULL) ? 0 : 1);
385 if (color) printf("\e[31;01m");
386 printf("--------------------------- ACCESS VIOLATION SUMMARY ---------------------------");
387 if (color) printf("\033[0m");
388 if (color) printf("\e[31;01m");
389 printf("\nLOG FILE = \"%s\"", sandbox_log);
390 if (color) printf("\033[0m");
392 printf("%s", buffer);
397 ("\e[31;01m--------------------------------------------------------------------------------\033[0m\n");
399 beep_count_env = getenv(ENV_SANDBOX_BEEP);
401 beep_count = atoi(beep_count_env);
403 beep_count = DEFAULT_BEEP_COUNT;
405 for (i = 0; i < beep_count; i++) {
407 if (i < beep_count - 1)
414 spawn_shell(char *argv_bash[])
416 #ifdef USE_SYSTEM_SHELL
424 if (NULL == argv_bash[i])
428 sh = (char *) realloc(sh, len + strlen(argv_bash[i]) + 5);
434 strcat(sh, argv_bash[i]);
437 //printf("%s\n", argv_bash[i]);
458 /* Child's process */
461 execv(argv_bash[0], argv_bash);
464 } else if (pid < 0) {
467 ret = waitpid(pid, &status, 0);
468 if ((-1 == ret) || (status > 0))
476 main(int argc, char **argv)
478 int i = 0, success = 1;
479 #ifdef USE_LD_SO_PRELOAD
480 int preload_file = -1;
482 int sandbox_log_presence = 0;
483 int sandbox_log_file = -1;
487 int *pids_array = NULL;
490 // char run_arg[255];
491 char portage_tmp_dir[PATH_MAX];
492 char var_tmp_dir[PATH_MAX];
493 char tmp_dir[PATH_MAX];
494 char sandbox_log[255];
495 char sandbox_debug_log[255];
496 char sandbox_dir[255];
497 char sandbox_lib[255];
498 char *sandbox_pids_file;
499 char sandbox_rc[255];
500 char pid_string[255];
501 char **argv_bash = NULL;
503 char *run_str = "-c";
504 char *home_dir = NULL;
505 char *tmp_string = NULL;
506 #ifdef USE_LD_SO_PRELOAD
507 char **preload_array = NULL;
508 int num_of_preloads = 0;
511 /* Only print info if called with no arguments .... */
517 ("========================== Gentoo linux path sandbox ===========================\n");
519 /* check if a sandbox is already running */
520 if (NULL != getenv(ENV_SANDBOX_ON)) {
522 "Not launching a new sandbox instance\nAnother one is already running in this process hierarchy.\n");
526 /* determine the location of all the sandbox support files */
528 printf("Detection of the support files.\n");
530 /* Generate base sandbox path */
531 tmp_string = get_sandbox_path(argv[0]);
532 strncpy(sandbox_dir, tmp_string, 254);
536 strcat(sandbox_dir, "/");
538 /* Generate sandbox lib path */
539 tmp_string = get_sandbox_lib(sandbox_dir);
540 strncpy(sandbox_lib, tmp_string, 254);
545 /* Generate sandbox pids-file path */
546 sandbox_pids_file = get_sandbox_pids_file();
548 /* Generate sandbox bashrc path */
549 tmp_string = get_sandbox_rc(sandbox_dir);
550 strncpy(sandbox_rc, tmp_string, 254);
555 /* verify the existance of required files */
557 printf("Verification of the required files.\n");
559 #ifndef SB_HAVE_64BIT_ARCH
560 if (file_exist(sandbox_lib, 0) <= 0) {
561 fprintf(stderr, "Could not open the sandbox library at '%s'.\n",
566 if (file_exist(sandbox_rc, 0) <= 0) {
567 fprintf(stderr, "Could not open the sandbox rc file at '%s'.\n",
571 #ifdef USE_LD_SO_PRELOAD
572 /* ensure that the /etc/ld.so.preload file contains an entry for the sandbox lib */
574 printf("Setting up the ld.so.preload file.\n");
576 /* check if the /etc/ld.so.preload is a regular file */
577 if (file_exist("/etc/ld.so.preload", 1) < 0) {
578 fprintf(stderr, ">>> /etc/ld.so.preload file is not a regular file\n");
583 /* Our r+ also will create the file if it doesn't exist */
584 preload_file = file_open("/etc/ld.so.preload", "r+", 1, 0644);
585 if (-1 == preload_file) {
586 preload_adaptable = 0;
590 /* Avoid permissions warnings if we're not root */
591 preload_adaptable = 0;
594 /* Only update /etc/ld.so.preload if we can write to it ... */
595 if (1 == preload_adaptable) {
596 /* Load entries of preload table */
597 num_of_preloads = load_preload_libs(preload_file, &preload_array);
599 /* Zero out our ld.so.preload file */
600 file_truncate(preload_file);
602 /* Write contents of preload file */
603 for (i = 0; i < num_of_preloads + 1; i++) {
604 /* First entry should be our sandbox library */
607 (preload_file, sandbox_lib,
608 strlen(sandbox_lib)) != strlen(sandbox_lib)) {
609 perror(">>> /etc/ld.so.preload file write");
614 /* Output all other preload entries */
616 (preload_file, preload_array[i - 1],
617 strlen(preload_array[i - 1])) != strlen(preload_array[i - 1])) {
618 perror(">>> /etc/ld.so.preload file write");
623 /* Don't forget the return character after each line! */
624 if (1 != write(preload_file, "\n", 1)) {
625 perror(">>> /etc/ld.so.preload file write");
631 for (i = 0; i < num_of_preloads; i++) {
632 if (preload_array[i])
633 free(preload_array[i]);
634 preload_array[i] = NULL;
639 preload_array = NULL;
642 /* That's all we needed to do with the preload file */
643 if (0 < preload_file)
644 file_close(preload_file);
648 /* set up the required environment variables */
650 printf("Setting up the required environment variables.\n");
652 /* Generate sandbox log full path */
653 tmp_string = get_sandbox_log();
654 strncpy(sandbox_log, tmp_string, 254);
659 setenv(ENV_SANDBOX_LOG, sandbox_log, 1);
661 snprintf(sandbox_debug_log, sizeof(sandbox_debug_log), "%s%s%s",
662 DEBUG_LOG_FILE_PREFIX, pid_string, LOG_FILE_EXT);
663 setenv(ENV_SANDBOX_DEBUG_LOG, sandbox_debug_log, 1);
665 home_dir = getenv("HOME");
668 setenv("HOME", home_dir, 1);
671 /* drobbins: we need to expand these paths using realpath() so that PORTAGE_TMPDIR
672 * can contain symlinks (example, /var is a symlink, /var/tmp is a symlink.) Without
673 * this, access is denied to /var/tmp, hurtin' ebuilds.
677 e = getenv("PORTAGE_TMPDIR");
678 if ( e && ( strlen(e) < sizeof(portage_tmp_dir)-1 ) && (strlen(e) > 1) )
679 realpath(e, portage_tmp_dir);
682 realpath("/var/tmp", var_tmp_dir);
683 realpath("/tmp", tmp_dir);
685 setenv(ENV_SANDBOX_DIR, sandbox_dir, 1);
686 setenv(ENV_SANDBOX_LIB, sandbox_lib, 1);
687 setenv("LD_PRELOAD", sandbox_lib, 1);
689 if (!getenv(ENV_SANDBOX_DENY))
690 setenv(ENV_SANDBOX_DENY, LD_PRELOAD_FILE, 1);
692 if (!getenv(ENV_SANDBOX_READ))
693 setenv(ENV_SANDBOX_READ, "/", 1);
695 /* Set up Sandbox Write path */
696 setenv_sandbox_write(home_dir, portage_tmp_dir, var_tmp_dir, tmp_dir);
697 setenv_sandbox_predict(home_dir);
699 setenv(ENV_SANDBOX_ON, "1", 0);
701 /* if the portage temp dir was present, cd into it */
702 if (NULL != portage_tmp_dir)
703 chdir(portage_tmp_dir);
705 argv_bash = (char **) malloc(6 * sizeof (char *));
706 argv_bash[0] = strdup("/bin/bash");
707 argv_bash[1] = strdup("-rcfile");
708 argv_bash[2] = strdup(sandbox_rc);
713 argv_bash[3] = strdup(run_str); /* "-c" */
715 argv_bash[4] = NULL; /* strdup(run_arg); */
719 for (i = 1; i < argc; i++) {
720 if (NULL == argv_bash[4])
723 len = strlen(argv_bash[4]);
726 (char *) realloc(argv_bash[4],
727 (len + strlen(argv[i]) + 2) * sizeof (char));
732 strcat(argv_bash[4], " ");
734 strcat(argv_bash[4], argv[i]);
738 /* set up the required signal handlers */
739 signal(SIGHUP, &stop);
740 signal(SIGINT, &stop);
741 signal(SIGQUIT, &stop);
742 signal(SIGTERM, &stop);
744 /* this one should NEVER be set in ebuilds, as it is the one
745 * private thing libsandbox.so use to test if the sandbox
746 * should be active for this pid, or not.
748 * azarah (3 Aug 2002)
751 setenv("SANDBOX_ACTIVE", "armedandready", 1);
753 /* Load our PID into PIDs file */
755 if (file_exist(sandbox_pids_file, 1) < 0) {
757 fprintf(stderr, ">>> %s is not a regular file\n", sandbox_pids_file);
759 pids_file = file_open(sandbox_pids_file, "r+", 1, 0664, "portage");
764 /* Grab still active pids */
765 num_of_pids = load_active_pids(pids_file, &pids_array);
768 file_truncate(pids_file);
770 /* Output active pids, and append our pid */
771 for (i = 0; i < num_of_pids + 1; i++) {
772 /* Time for our entry */
773 if (i == num_of_pids)
774 sprintf(pid_string, "%d\n", getpid());
776 sprintf(pid_string, "%d\n", pids_array[i]);
778 if (write(pids_file, pid_string, strlen(pid_string)) !=
779 strlen(pid_string)) {
780 perror(">>> pids file write");
785 /* Clean pids_array */
791 /* We're done with the pids file */
792 file_close(pids_file);
795 /* Something went wrong, bail out */
797 perror(">>> pids file write");
801 /* STARTING PROTECTED ENVIRONMENT */
803 printf("The protected environment has been started.\n");
805 ("--------------------------------------------------------------------------------\n");
809 printf("Shell being started in forked process.\n");
812 if (!spawn_shell(argv_bash)) {
814 fprintf(stderr, ">>> shell process failed to spawn\n");
818 /* Free bash stuff */
819 for (i = 0; i < 6; i++) {
829 printf("Cleaning up sandbox process\n");
835 ("========================== Gentoo linux path sandbox ===========================\n");
836 printf("The protected environment has been shut down.\n");
839 if (file_exist(sandbox_log, 0)) {
840 sandbox_log_presence = 1;
842 if (!print_sandbox_log(sandbox_log))
850 sandbox_log_file = -1;
851 } else if (print_debug) {
853 ("--------------------------------------------------------------------------------\n");
856 if ((sandbox_log_presence) || (!success))
863 // vim:expandtab noai:cindent ai