X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=src%2Fbox.c;h=7bff340ce85cbb993c5ebc0e7dba8d8a584f15c7;hb=24a6e512fa3427c0f7f3003723093ff38ec11637;hp=062110f27200e8c0b0966b9e550a0276f8dbb1ee;hpb=006578d4fa9bc8c3d298e9f691a03b9dbff595ea;p=eval.git diff --git a/src/box.c b/src/box.c index 062110f..7bff340 100644 --- a/src/box.c +++ b/src/box.c @@ -1,7 +1,7 @@ /* * A Simple Testing Sandbox * - * (c) 2001--2004 Martin Mares + * (c) 2001--2007 Martin Mares */ #define _LARGEFILE64_SOURCE @@ -29,9 +29,9 @@ #define UNUSED __attribute__((unused)) static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */ -static int timeout; +static int timeout; /* milliseconds */ +static int wall_timeout; static int pass_environ; -static int use_wall_clock; static int file_access; static int verbose; static int memory_limit; @@ -42,7 +42,7 @@ static char *set_cwd; static pid_t box_pid; static int is_ptraced; static volatile int timer_tick; -static time_t start_time; +static struct timeval start_time; static int ticks_per_sec; #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0 @@ -78,7 +78,7 @@ die(char *msg, ...) } static void __attribute__((format(printf,1,2))) -log(char *msg, ...) +msg(char *msg, ...) { va_list args; va_start(args, msg); @@ -97,7 +97,7 @@ valid_filename(unsigned long addr) static int mem_fd; if (!file_access) - die("File access forbidden."); + die("File access forbidden"); if (file_access >= 9) return; @@ -118,21 +118,21 @@ valid_filename(unsigned long addr) if (l > remains) l = remains; if (!l) - die("Access to file with name too long."); + die("Access to file with name too long"); if (long_seek(mem_fd, addr, SEEK_SET) < 0) die("long_seek(mem): %m"); remains = read(mem_fd, end, l); if (remains < 0) die("read(mem): %m"); if (!remains) - die("Access to file with name out of memory."); + die("Access to file with name out of memory"); end += l; addr += l; } } while (*p++); - log("[%s] ", namebuf); + msg("[%s] ", namebuf); if (file_access >= 3) return; if (!strchr(namebuf, '/') && strcmp(namebuf, "..")) @@ -141,17 +141,19 @@ valid_filename(unsigned long addr) { if ((!strncmp(namebuf, "/etc/", 5) || !strncmp(namebuf, "/lib/", 5) || - !strncmp(namebuf, "/usr/lib/", 9)) + !strncmp(namebuf, "/usr/lib/", 9) || + !strncmp(namebuf, "/opt/lib/", 9)) && !strstr(namebuf, "..")) return; if (!strcmp(namebuf, "/dev/null") || !strcmp(namebuf, "/dev/zero") || !strcmp(namebuf, "/proc/meminfo") || !strcmp(namebuf, "/proc/self/stat") || + !strcmp(namebuf, "/proc/self/exe") || /* Needed by FPC 2.0.x runtime */ !strncmp(namebuf, "/usr/share/zoneinfo/", 20)) return; } - die("Forbidden access to file `%s'.", namebuf); + die("Forbidden access to file `%s'", namebuf); } static int @@ -159,101 +161,114 @@ valid_syscall(struct user *u) { switch (u->regs.orig_eax) { - case SYS_execve: + case __NR_execve: { static int exec_counter; return !exec_counter++; } - case SYS_open: - case SYS_creat: - case SYS_unlink: - case SYS_oldstat: - case SYS_access: - case SYS_oldlstat: - case SYS_truncate: - case SYS_stat: - case SYS_lstat: - case SYS_truncate64: - case SYS_stat64: - case SYS_lstat64: + case __NR_open: + case __NR_creat: + case __NR_unlink: + case __NR_oldstat: + case __NR_access: + case __NR_oldlstat: + case __NR_truncate: + case __NR_stat: + case __NR_lstat: + case __NR_truncate64: + case __NR_stat64: + case __NR_lstat64: + case __NR_readlink: valid_filename(u->regs.ebx); return 1; - case SYS_exit: - case SYS_read: - case SYS_write: - case SYS_close: - case SYS_lseek: - case SYS_getpid: - case SYS_getuid: - case SYS_oldfstat: - case SYS_dup: - case SYS_brk: - case SYS_getgid: - case SYS_geteuid: - case SYS_getegid: - case SYS_dup2: - case SYS_ftruncate: - case SYS_fstat: - case SYS_personality: - case SYS__llseek: - case SYS_readv: - case SYS_writev: - case SYS_getresuid: - case SYS_pread: - case SYS_pwrite: - case SYS_ftruncate64: - case SYS_fstat64: - case SYS_fcntl: - case SYS_fcntl64: - case SYS_mmap: - case SYS_munmap: - case SYS_ioctl: - case SYS_uname: - case 252: + case __NR_exit: + case __NR_read: + case __NR_write: + case __NR_close: + case __NR_lseek: + case __NR_getpid: + case __NR_getuid: + case __NR_oldfstat: + case __NR_dup: + case __NR_brk: + case __NR_getgid: + case __NR_geteuid: + case __NR_getegid: + case __NR_dup2: + case __NR_ftruncate: + case __NR_fstat: + case __NR_personality: + case __NR__llseek: + case __NR_readv: + case __NR_writev: + case __NR_getresuid: +#ifdef __NR_pread64 + case __NR_pread64: + case __NR_pwrite64: +#else + case __NR_pread: + case __NR_pwrite: +#endif + case __NR_ftruncate64: + case __NR_fstat64: + case __NR_fcntl: + case __NR_fcntl64: + case __NR_mmap: + case __NR_munmap: + case __NR_ioctl: + case __NR_uname: + case __NR_gettid: + case __NR_set_thread_area: + case __NR_get_thread_area: + case __NR_exit_group: return 1; - case SYS_time: - case SYS_alarm: - case SYS_pause: - case SYS_signal: - case SYS_fchmod: - case SYS_sigaction: - case SYS_sgetmask: - case SYS_ssetmask: - case SYS_sigsuspend: - case SYS_sigpending: - case SYS_getrlimit: - case SYS_getrusage: - case SYS_gettimeofday: - case SYS_select: - case SYS_readdir: - case SYS_setitimer: - case SYS_getitimer: - case SYS_sigreturn: - case SYS_mprotect: - case SYS_sigprocmask: - case SYS_getdents: - case SYS_getdents64: - case SYS__newselect: - case SYS_fdatasync: - case SYS_mremap: - case SYS_poll: - case SYS_getcwd: - case SYS_nanosleep: - case SYS_rt_sigreturn: - case SYS_rt_sigaction: - case SYS_rt_sigprocmask: - case SYS_rt_sigpending: - case SYS_rt_sigtimedwait: - case SYS_rt_sigqueueinfo: - case SYS_rt_sigsuspend: - case SYS_mmap2: - case SYS__sysctl: + case __NR_time: + case __NR_alarm: + case __NR_pause: + case __NR_signal: + case __NR_fchmod: + case __NR_sigaction: + case __NR_sgetmask: + case __NR_ssetmask: + case __NR_sigsuspend: + case __NR_sigpending: + case __NR_getrlimit: + case __NR_getrusage: + case __NR_gettimeofday: + case __NR_select: + case __NR_readdir: + case __NR_setitimer: + case __NR_getitimer: + case __NR_sigreturn: + case __NR_mprotect: + case __NR_sigprocmask: + case __NR_getdents: + case __NR_getdents64: + case __NR__newselect: + case __NR_fdatasync: + case __NR_mremap: + case __NR_poll: + case __NR_getcwd: + case __NR_nanosleep: + case __NR_rt_sigreturn: + case __NR_rt_sigaction: + case __NR_rt_sigprocmask: + case __NR_rt_sigpending: + case __NR_rt_sigtimedwait: + case __NR_rt_sigqueueinfo: + case __NR_rt_sigsuspend: + case __NR_mmap2: + case __NR__sysctl: return (filter_syscalls == 1); - case SYS_times: + case __NR_times: return allow_times; - case SYS_kill: + case __NR_kill: if (u->regs.ebx == box_pid) - die("Commited suicide by signal %d.", (int)u->regs.ecx); + die("Committed suicide by signal %d", (int)u->regs.ecx); + return 0; + case __NR_tgkill: + if (u->regs.ebx == box_pid && u->regs.ecx == box_pid) + die("Committed suicide by signal %d", (int)u->regs.edx); return 0; default: return 0; @@ -272,20 +287,28 @@ static void signal_int(int unused UNUSED) { /* Interrupts are fatal, so no synchronization requirements. */ - die("Interrupted."); + die("Interrupted"); } static void check_timeout(void) { - int sec; - - if (use_wall_clock) - sec = time(NULL) - start_time; - else + if (wall_timeout) + { + struct timeval now, wall; + int wall_ms; + gettimeofday(&now, NULL); + timersub(&now, &start_time, &wall); + wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000; + if (wall_ms > wall_timeout) + die("Time limit exceeded (wall clock)"); + if (verbose > 1) + fprintf(stderr, "[wall time check: %d msec]\n", wall_ms); + } + if (timeout) { char buf[4096], *x; - int c, utime, stime; + int c, utime, stime, ms; static int proc_status_fd; if (!proc_status_fd) { @@ -313,12 +336,12 @@ check_timeout(void) x++; if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2) die("proc syntax error 2"); - sec = (utime + stime)/ticks_per_sec; + ms = (utime + stime) * 1000 / ticks_per_sec; + if (verbose > 1) + fprintf(stderr, "[time check: %d msec]\n", ms); + if (ms > timeout) + die("Time limit exceeded"); } - if (verbose > 1) - fprintf(stderr, "[timecheck: %d seconds]\n", sec); - if (sec > timeout) - die("Time limit exceeded."); } static void @@ -331,11 +354,11 @@ boxkeeper(void) bzero(&sa, sizeof(sa)); sa.sa_handler = signal_int; sigaction(SIGINT, &sa, NULL); - start_time = time(NULL); + gettimeofday(&start_time, NULL); ticks_per_sec = sysconf(_SC_CLK_TCK); if (ticks_per_sec <= 0) die("Invalid ticks_per_sec!"); - if (timeout) + if (timeout || wall_timeout) { sa.sa_handler = signal_alarm; sigaction(SIGALRM, &sa, NULL); @@ -362,22 +385,30 @@ boxkeeper(void) die("wait4: unknown pid %d exited!", p); if (WIFEXITED(stat)) { - struct timeval total; - int wall; + struct timeval total, now, wall; + int total_ms, wall_ms; box_pid = 0; if (WEXITSTATUS(stat)) - die("Exited with error status %d.", WEXITSTATUS(stat)); + die("Exited with error status %d", WEXITSTATUS(stat)); timeradd(&rus.ru_utime, &rus.ru_stime, &total); - wall = time(NULL) - start_time; - if ((use_wall_clock ? wall : total.tv_sec) > timeout) - die("Time limit exceeded (after exit)."); - fprintf(stderr, "OK (%d sec real, %d sec wall, %d syscalls)\n", (int) total.tv_sec, wall, syscall_count); + total_ms = total.tv_sec*1000 + total.tv_usec/1000; + gettimeofday(&now, NULL); + timersub(&now, &start_time, &wall); + wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000; + if (timeout && total_ms > timeout) + die("Time limit exceeded"); + if (wall_timeout && wall_ms > wall_timeout) + die("Time limit exceeded (wall clock)"); + fprintf(stderr, "OK (%d.%03d sec real, %d.%03d sec wall, %d syscalls)\n", + (int) total.tv_sec, (int) total.tv_usec/1000, + (int) wall.tv_sec, (int) wall.tv_usec/1000, + syscall_count); exit(0); } if (WIFSIGNALED(stat)) { box_pid = 0; - die("Caught fatal signal %d.", WTERMSIG(stat)); + die("Caught fatal signal %d", WTERMSIG(stat)); } if (WIFSTOPPED(stat)) { @@ -390,10 +421,10 @@ boxkeeper(void) die("ptrace(PTRACE_GETREGS): %m"); stop_count++; if (!stop_count) /* Traceme request */ - log(">> Traceme request caught\n"); + msg(">> Traceme request caught\n"); else if (stop_count & 1) /* Syscall entry */ { - log(">> Syscall %3ld (%08lx,%08lx,%08lx) ", u.regs.orig_eax, u.regs.ebx, u.regs.ecx, u.regs.edx); + msg(">> Syscall %3ld (%08lx,%08lx,%08lx) ", u.regs.orig_eax, u.regs.ebx, u.regs.ecx, u.regs.edx); syscall_count++; if (!valid_syscall(&u)) { @@ -406,20 +437,20 @@ boxkeeper(void) u.regs.orig_eax = 0xffffffff; if (ptrace(PTRACE_SETREGS, box_pid, NULL, &u) < 0) die("ptrace(PTRACE_SETREGS): %m"); - die("Forbidden syscall %d.", sys); + die("Forbidden syscall %d", sys); } } else /* Syscall return */ - log("= %ld\n", u.regs.eax); + msg("= %ld\n", u.regs.eax); ptrace(PTRACE_SYSCALL, box_pid, 0, 0); } else if (sig != SIGSTOP && sig != SIGXCPU && sig != SIGXFSZ) { - log(">> Signal %d\n", sig); + msg(">> Signal %d\n", sig); ptrace(PTRACE_SYSCALL, box_pid, 0, sig); } else - die("Received signal %d.", sig); + die("Received signal %d", sig); } else die("wait4: unknown status %x, giving up!", stat); @@ -431,7 +462,7 @@ box_inside(int argc, char **argv) { struct rlimit rl; char *args[argc+1]; - char *env[1] = { NULL }; + char *env[] = { "LIBC_FATAL_STDERR_=1", NULL }; memcpy(args, argv, argc * sizeof(char *)); args[argc] = NULL; @@ -481,10 +512,10 @@ Options:\n\ -i \tRedirect stdin from \n\ -m \tLimit address space to KB\n\ -o \tRedirect stdout to \n\ --t