X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=isolate%2Fisolate.c;h=c2e9b7162f98abf6c9329fbec090df137d37e211;hb=784505ffb97052532e2b1f4f2df81b301cba2e6a;hp=718724a29b34158b3c36e60abddbb4379f5ed12c;hpb=24551a2d797b1b470b416979675fe922aa1cc2fa;p=eval.git diff --git a/isolate/isolate.c b/isolate/isolate.c index 718724a..c2e9b71 100644 --- a/isolate/isolate.c +++ b/isolate/isolate.c @@ -48,19 +48,20 @@ static int verbose; static int memory_limit; static int stack_limit; static char *redir_stdin, *redir_stdout, *redir_stderr; -static char *set_cwd; + +static uid_t orig_uid; +static gid_t orig_gid; static pid_t box_pid; -static volatile int timer_tick; +static volatile sig_atomic_t timer_tick; static struct timeval start_time; static int ticks_per_sec; static int partial_line; +static char cleanup_cmd[256]; -static int mem_peak_kb; static int total_ms, wall_ms; static void die(char *msg, ...) NONRET; -static void sample_mem_peak(void); /*** Meta-files ***/ @@ -110,17 +111,25 @@ final_stats(struct rusage *rus) meta_printf("time:%d.%03d\n", total_ms/1000, total_ms%1000); meta_printf("time-wall:%d.%03d\n", wall_ms/1000, wall_ms%1000); - meta_printf("mem:%llu\n", (unsigned long long) mem_peak_kb * 1024); } /*** Messages and exits ***/ +static void +xsystem(const char *cmd) +{ + int ret = system(cmd); + if (ret < 0) + die("system(\"%s\"): %m", cmd); + if (!WIFEXITED(ret) || WEXITSTATUS(ret)) + die("system(\"%s\"): Exited with status %d", cmd, ret); +} + static void NONRET box_exit(int rc) { if (box_pid > 0) { - sample_mem_peak(); kill(-box_pid, SIGKILL); kill(box_pid, SIGKILL); meta_printf("killed:1\n"); @@ -135,6 +144,10 @@ box_exit(int rc) else final_stats(&rus); } + + if (rc < 2 && cleanup_cmd[0]) + xsystem(cleanup_cmd); + meta_close(); exit(rc); } @@ -343,7 +356,7 @@ setup_environment(void) return env; } -/*** FIXME ***/ +/*** The keeper process ***/ static void signal_alarm(int unused UNUSED) @@ -424,51 +437,6 @@ check_timeout(void) } } -static void -sample_mem_peak(void) -{ - /* - * We want to find out the peak memory usage of the process, which is - * maintained by the kernel, but unforunately it gets lost when the - * process exits (it is not reported in struct rusage). Therefore we - * have to sample it whenever we suspect that the process is about - * to exit. - */ - char buf[PROC_BUF_SIZE], *x; - static int proc_status_fd; - read_proc_file(buf, "status", &proc_status_fd); - - x = buf; - while (*x) - { - char *key = x; - while (*x && *x != ':' && *x != '\n') - x++; - if (!*x || *x == '\n') - break; - *x++ = 0; - while (*x == ' ' || *x == '\t') - x++; - - char *val = x; - while (*x && *x != '\n') - x++; - if (!*x) - break; - *x++ = 0; - - if (!strcmp(key, "VmPeak")) - { - int peak = atoi(val); - if (peak > mem_peak_kb) - mem_peak_kb = peak; - } - } - - if (verbose > 1) - msg("[mem-peak: %u KB]\n", mem_peak_kb); -} - static void box_keeper(void) { @@ -524,10 +492,9 @@ box_keeper(void) if (wall_timeout && wall_ms > wall_timeout) err("TO: Time limit exceeded (wall clock)"); flush_line(); - fprintf(stderr, "OK (%d.%03d sec real, %d.%03d sec wall, %d MB)\n", + fprintf(stderr, "OK (%d.%03d sec real, %d.%03d sec wall)\n", total_ms/1000, total_ms%1000, - wall_ms/1000, wall_ms%1000, - (mem_peak_kb + 1023) / 1024); + wall_ms/1000, wall_ms%1000); box_exit(0); } if (WIFSIGNALED(stat)) @@ -549,10 +516,12 @@ box_keeper(void) } } +/*** The process running inside the box ***/ + static void setup_root(void) { - umask(0022); + umask(0027); if (mkdir("root", 0777) < 0 && errno != EEXIST) die("mkdir('root'): %m"); @@ -561,7 +530,7 @@ setup_root(void) die("Cannot mount root ramdisk: %m"); // FIXME: Make the list of bind-mounts configurable - // FIXME: Virtual dev? + // FIXME: Virtual /dev? // FIXME: Read-only mounts? static const char * const dirs[] = { "box", "/bin", "/lib", "/usr", "/dev" }; @@ -570,7 +539,7 @@ setup_root(void) const char *d = dirs[i]; char buf[1024]; // FIXME sprintf(buf, "root/%s", (d[0] == '/' ? d+1 : d)); - printf("Binding %s on %s\n", d, buf); + msg("Binding %s on %s\n", d, buf); if (mkdir(buf, 0777) < 0) die("mkdir(%s): %m", buf); if (mount(d, buf, "none", MS_BIND | MS_NOSUID | MS_NODEV, "") < 0) @@ -666,34 +635,33 @@ box_inside(void *arg) static void prepare(void) { - // FIXME: Move chdir to common code? - if (chdir(BOX_DIR) < 0) - die("chdir(%s): %m", BOX_DIR); - - if (system("./prepare")) - die("Prepare hook failed"); + msg("Preparing sandbox directory\n"); + xsystem("rm -rf box"); + if (mkdir("box", 0700) < 0) + die("Cannot create box: %m"); + if (chown("box", orig_uid, orig_gid) < 0) + die("Cannot chown box: %m"); } static void cleanup(void) { - if (chdir(BOX_DIR) < 0) - die("chdir(%s): %m", BOX_DIR); - - if (system("./cleanup")) - die("Prepare hook failed"); + msg("Deleting sandbox directory\n"); + xsystem("rm -rf box"); } static void run(char **argv) { - if (chdir(BOX_DIR) < 0) - die("chdir(%s): %m", BOX_DIR); - struct stat st; if (stat("box", &st) < 0 || !S_ISDIR(st.st_mode)) die("Box directory not found, did you run `isolate --prepare'?"); + char cmd[256]; + snprintf(cmd, sizeof(cmd), "chown -R %d.%d box", BOX_UID, BOX_GID); + xsystem(cmd); + snprintf(cleanup_cmd, sizeof(cleanup_cmd), "chown -R %d.%d box", orig_uid, orig_gid); + box_pid = clone( box_inside, // Function to execute as the body of the new process argv, // Pass our stack @@ -706,53 +674,74 @@ run(char **argv) box_keeper(); } -// FIXME: Prune (and also the option list) +static void +show_version(void) +{ + // FIXME + printf("Process isolator 0.0\n"); + printf("(c) 2012 Martin Mares \n\n"); + printf("Sandbox directory: %s\n", BOX_DIR); + printf("Sandbox credentials: uid=%u gid=%u\n", BOX_UID, BOX_GID); +} + static void usage(void) { fprintf(stderr, "Invalid arguments!\n"); printf("\ -Usage: box [] -- \n\ +Usage: isolate [] \n\ \n\ Options:\n\ --a \tSet file access level (0=none, 1=cwd, 2=/etc,/lib,..., 3=whole fs, 9=no checks; needs -f)\n\ --c \tChange directory to first\n\ --e\t\tInherit full environment of the parent process\n\ --E \tInherit the environment variable from the parent process\n\ --E =\tSet the environment variable to ; unset it if is empty\n\ --f\t\tFilter system calls (-ff=very restricted)\n\ --i \tRedirect stdin from \n\ --k \tLimit stack size to KB (default: 0=unlimited)\n\ --m \tLimit address space to KB\n\ --M \tOutput process information to (name:value)\n\ --o \tRedirect stdout to \n\ --p \tPermit access to the specified path (or subtree if it ends with a `/')\n\ --p =\tDefine action for the specified path (=yes/no)\n\ --r \tRedirect stderr to \n\ --s \tPermit the specified syscall (be careful)\n\ --s =\tDefine action for the specified syscall (=yes/no/file)\n\ --t