X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=box%2Fbox.c;h=1394a85d5f62d95b6d581d48d4ca14acd2a2a519;hb=e6f07a3c51c1117f3f95fa846dd042b5a4a1e201;hp=40f96a960fa0e41044a245b2ccf7329178ffa34a;hpb=04420f91fec8942f1fd83347f1a21feaaacf12b1;p=eval.git diff --git a/box/box.c b/box/box.c index 40f96a9..1394a85 100644 --- a/box/box.c +++ b/box/box.c @@ -47,15 +47,6 @@ static int ticks_per_sec; static int exec_seen; static int partial_line; -#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0 -/* glibc 2.1 or newer -> has lseek64 */ -#define long_seek(f,o,w) lseek64(f,o,w) -#else -/* Touching clandestine places in glibc */ -extern loff_t llseek(int fd, loff_t pos, int whence); -#define long_seek(f,o,w) llseek(f,o,w) -#endif - static void die(char *msg, ...) NONRET; /*** Meta-files ***/ @@ -103,7 +94,6 @@ final_stats(struct rusage *rus) timeradd(&rus->ru_utime, &rus->ru_stime, &total); total_ms = total.tv_sec*1000 + total.tv_usec/1000; gettimeofday(&now, NULL); - // FIXME: We are not guaranteed to have start_time always initialized timersub(&now, &start_time, &wall); wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000; @@ -143,18 +133,42 @@ flush_line(void) partial_line = 0; } +/* Report an error of the sandbox itself */ static void NONRET __attribute__((format(printf,1,2))) die(char *msg, ...) { va_list args; va_start(args, msg); flush_line(); - vfprintf(stderr, msg, args); + char buf[1024]; + vsnprintf(buf, sizeof(buf), msg, args); + meta_printf("status:XX\nmessage:%s\n", buf); + fputs(buf, stderr); + fputc('\n', stderr); + box_exit(2); +} + +/* Report an error of the program inside the sandbox */ +static void NONRET __attribute__((format(printf,1,2))) +err(char *msg, ...) +{ + va_list args; + va_start(args, msg); + flush_line(); + if (msg[0] && msg[1] && msg[2] == ':' && msg[3] == ' ') + { + meta_printf("status:%c%c\n", msg[0], msg[1]); + msg += 4; + } + char buf[1024]; + vsnprintf(buf, sizeof(buf), msg, args); + meta_printf("message:%s\n", buf); + fputs(buf, stderr); fputc('\n', stderr); box_exit(1); - // FIXME: exit(2) for errors of the box itself } +/* Write a message, but only if in verbose mode */ static void __attribute__((format(printf,1,2))) msg(char *msg, ...) { @@ -248,12 +262,14 @@ static unsigned char syscall_action[NUM_ACTIONS] = { S(fcntl) = A_YES, S(fcntl64) = A_YES, S(mmap) = A_YES, + S(mmap2) = A_YES, S(munmap) = A_YES, S(ioctl) = A_YES, S(uname) = A_YES, S(gettid) = A_YES, S(set_thread_area) = A_YES, S(get_thread_area) = A_YES, + S(set_tid_address) = A_YES, S(exit_group) = A_YES, // Syscalls permitted only in liberal mode @@ -293,7 +309,6 @@ static unsigned char syscall_action[NUM_ACTIONS] = { S(rt_sigtimedwait) = A_YES | A_LIBERAL, S(rt_sigqueueinfo) = A_YES | A_LIBERAL, S(rt_sigsuspend) = A_YES | A_LIBERAL, - S(mmap2) = A_YES | A_LIBERAL, S(_sysctl) = A_YES | A_LIBERAL, #undef S }; @@ -567,7 +582,7 @@ valid_filename(unsigned long addr) static int mem_fd; if (!file_access) - die("File access forbidden"); + err("FA: File access forbidden"); if (file_access >= 9) return; @@ -588,14 +603,14 @@ valid_filename(unsigned long addr) if (l > remains) l = remains; if (!l) - die("Access to file with name too long"); - if (long_seek(mem_fd, addr, SEEK_SET) < 0) - die("long_seek(mem): %m"); + err("FA: Access to file with name too long"); + if (lseek64(mem_fd, addr, SEEK_SET) < 0) + die("lseek64(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"); + err("FA: Access to file with name out of memory"); end += l; addr += l; } @@ -625,7 +640,7 @@ valid_filename(unsigned long addr) act = match_path_rule(&default_path_rules[i], namebuf); if (act != A_YES) - die("Forbidden access to file `%s'", namebuf); + err("FA: Forbidden access to file `%s'", namebuf); } static int @@ -657,11 +672,17 @@ valid_syscall(struct user *u) { case __NR_kill: if (u->regs.ebx == box_pid) - die("Committed suicide by signal %d", (int)u->regs.ecx); + { + meta_printf("exitsig:%d\n", (int)u->regs.ecx); + err("SG: 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); + { + meta_printf("exitsig:%d\n", (int)u->regs.edx); + err("SG: Committed suicide by signal %d", (int)u->regs.edx); + } return 0; default: return 0; @@ -680,7 +701,8 @@ static void signal_int(int unused UNUSED) { /* Interrupts are fatal, so no synchronization requirements. */ - die("Interrupted"); + meta_printf("exitsig:%d\n", SIGINT); + err("SG: Interrupted"); } static void @@ -694,7 +716,7 @@ check_timeout(void) 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)"); + err("TO: Time limit exceeded (wall clock)"); if (verbose > 1) fprintf(stderr, "[wall time check: %d msec]\n", wall_ms); } @@ -733,7 +755,7 @@ check_timeout(void) if (verbose > 1) fprintf(stderr, "[time check: %d msec]\n", ms); if (ms > timeout) - die("Time limit exceeded"); + err("TO: Time limit exceeded"); } } @@ -780,13 +802,23 @@ boxkeeper(void) { box_pid = 0; final_stats(&rus); - // FIXME: If the process has exited before being ptraced, signal an internal error if (WEXITSTATUS(stat)) - die("Exited with error status %d", WEXITSTATUS(stat)); + { + if (syscall_count) + { + meta_printf("exitcode:%d\n", WEXITSTATUS(stat)); + err("RE: Exited with error status %d", WEXITSTATUS(stat)); + } + else + { + // Internal error happened inside the child process and it has been already reported. + box_exit(2); + } + } if (timeout && total_ms > timeout) - die("Time limit exceeded"); + err("TO: Time limit exceeded"); if (wall_timeout && wall_ms > wall_timeout) - die("Time limit exceeded (wall clock)"); + err("TO: Time limit exceeded (wall clock)"); flush_line(); fprintf(stderr, "OK (%d.%03d sec real, %d.%03d sec wall, %d syscalls)\n", total_ms/1000, total_ms%1000, @@ -797,7 +829,8 @@ boxkeeper(void) if (WIFSIGNALED(stat)) { box_pid = 0; - die("Caught fatal signal %d%s", WTERMSIG(stat), (syscall_count ? "" : " during startup")); + meta_printf("exitsig:%d\n", WTERMSIG(stat)); + err("SG: Caught fatal signal %d%s", WTERMSIG(stat), (syscall_count ? "" : " during startup")); } if (WIFSTOPPED(stat)) { @@ -834,7 +867,7 @@ boxkeeper(void) u.regs.orig_eax = 0xffffffff; if (ptrace(PTRACE_SETREGS, box_pid, NULL, &u) < 0) die("ptrace(PTRACE_SETREGS): %m"); - die("Forbidden syscall %s", syscall_name(sys, namebuf)); + err("FO: Forbidden syscall %s", syscall_name(sys, namebuf)); } } else /* Syscall return */ @@ -847,7 +880,10 @@ boxkeeper(void) ptrace(PTRACE_SYSCALL, box_pid, 0, sig); } else - die("Received signal %d", sig); + { + meta_printf("exitsig:%d", sig); + err("SG: Received signal %d", sig); + } } else die("wait4: unknown status %x, giving up!", stat); @@ -934,7 +970,7 @@ Options:\n\ -v\t\tBe verbose (use multiple times for even more verbosity)\n\ -w