static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */
static int timeout; /* milliseconds */
static int wall_timeout;
+static int extra_timeout;
static int pass_environ;
static int file_access;
static int verbose;
ptrace(PTRACE_KILL, box_pid);
kill(-box_pid, SIGKILL);
kill(box_pid, SIGKILL);
+ meta_printf("killed:1\n");
struct rusage rus;
int stat;
A_YES, // Always permit
A_FILENAME, // Permit if arg1 is a known filename
A_ACTION_MASK = 15,
+ A_NO_RETVAL = 32, // Does not return a value
A_SAMPLE_MEM = 64, // Sample memory usage before the syscall
A_LIBERAL = 128, // Valid only in liberal mode
// Must fit in a unsigned char
S(readdir) = A_YES | A_LIBERAL,
S(setitimer) = A_YES | A_LIBERAL,
S(getitimer) = A_YES | A_LIBERAL,
- S(sigreturn) = A_YES | A_LIBERAL,
+ S(sigreturn) = A_YES | A_LIBERAL | A_NO_RETVAL,
S(mprotect) = A_YES | A_LIBERAL,
S(sigprocmask) = A_YES | A_LIBERAL,
S(getdents) = A_YES | A_LIBERAL,
S(poll) = A_YES | A_LIBERAL,
S(getcwd) = A_YES | A_LIBERAL,
S(nanosleep) = A_YES | A_LIBERAL,
- S(rt_sigreturn) = A_YES | A_LIBERAL,
+ S(rt_sigreturn) = A_YES | A_LIBERAL | A_NO_RETVAL,
S(rt_sigaction) = A_YES | A_LIBERAL,
S(rt_sigprocmask) = A_YES | A_LIBERAL,
S(rt_sigpending) = A_YES | A_LIBERAL,
ms = (utime + stime) * 1000 / ticks_per_sec;
if (verbose > 1)
fprintf(stderr, "[time check: %d msec]\n", ms);
- if (ms > timeout)
+ if (ms > timeout && ms > extra_timeout)
err("TO: Time limit exceeded");
}
}
int sig = WSTOPSIG(stat);
if (sig == SIGTRAP)
{
+ if (verbose > 2)
+ msg("[ptrace status %08x] ", stat);
+ static int stop_count;
+ if (!stop_count++) /* Traceme request */
+ msg(">> Traceme request caught\n");
+ else
+ err("SG: Breakpoint");
+ ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
+ }
+ else if (sig == (SIGTRAP | 0x80))
+ {
+ if (verbose > 2)
+ msg("[ptrace status %08x] ", stat);
struct user u;
- static int stop_count = -1;
+ static unsigned int sys_tick, last_sys, last_act;
if (ptrace(PTRACE_GETREGS, box_pid, NULL, &u) < 0)
die("ptrace(PTRACE_GETREGS): %m");
- if (u.regs.orig_eax < 0) /* Process issued a breakpoint instruction */
- err("SG: Breakpoint");
- stop_count++;
- if (!stop_count) /* Traceme request */
- msg(">> Traceme request caught\n");
- else if (stop_count & 1) /* Syscall entry */
+ unsigned int sys = u.regs.orig_eax;
+ if (++sys_tick & 1) /* Syscall entry */
{
char namebuf[32];
int act;
- msg(">> Syscall %-12s (%08lx,%08lx,%08lx) ", syscall_name(u.regs.orig_eax, namebuf), u.regs.ebx, u.regs.ecx, u.regs.edx);
+ msg(">> Syscall %-12s (%08lx,%08lx,%08lx) ", syscall_name(sys, namebuf), u.regs.ebx, u.regs.ecx, u.regs.edx);
if (!exec_seen)
{
msg("[master] ");
- if (u.regs.orig_eax == __NR_execve)
+ if (sys == __NR_execve)
exec_seen = 1;
}
else if ((act = valid_syscall(&u)) >= 0)
{
+ last_act = act;
syscall_count++;
if (act & A_SAMPLE_MEM)
sample_mem_peak();
* so we have to change it to something harmless (e.g., an undefined
* syscall) and make the program continue.
*/
- unsigned int sys = u.regs.orig_eax;
u.regs.orig_eax = 0xffffffff;
if (ptrace(PTRACE_SETREGS, box_pid, NULL, &u) < 0)
die("ptrace(PTRACE_SETREGS): %m");
err("FO: Forbidden syscall %s", syscall_name(sys, namebuf));
}
+ last_sys = sys;
}
else /* Syscall return */
- msg("= %ld\n", u.regs.eax);
+ {
+ if (sys == 0xffffffff)
+ {
+ /* Some syscalls (sigreturn et al.) do not return a value */
+ if (!(last_act & A_NO_RETVAL))
+ err("XX: Syscall does not return, but it should");
+ }
+ else
+ {
+ if (sys != last_sys)
+ err("XX: Mismatched syscall entry/exit");
+ }
+ if (last_act & A_NO_RETVAL)
+ msg("= ?\n");
+ else
+ msg("= %ld\n", u.regs.eax);
+ }
ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
}
- else if (sig != SIGSTOP && sig != SIGXCPU && sig != SIGXFSZ)
+ else if (sig == SIGSTOP)
+ {
+ msg(">> SIGSTOP\n");
+ if (ptrace(PTRACE_SETOPTIONS, box_pid, NULL, (void *) PTRACE_O_TRACESYSGOOD) < 0)
+ die("ptrace(PTRACE_SETOPTIONS): %m");
+ ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
+ }
+ else if (sig != SIGXCPU && sig != SIGXFSZ)
{
msg(">> Signal %d\n", sig);
sample_mem_peak(); /* Signal might be fatal, so update mem-peak */
if (ptrace(PTRACE_TRACEME) < 0)
die("ptrace(PTRACE_TRACEME): %m");
/* Trick: Make sure that we are stopped until the boxkeeper wakes up. */
- signal(SIGCHLD, SIG_IGN);
- raise(SIGCHLD);
+ raise(SIGSTOP);
}
execve(args[0], args, env);
die("execve(\"%s\"): %m", args[0]);
-T\t\tAllow syscalls for measuring run time\n\
-v\t\tBe verbose (use multiple times for even more verbosity)\n\
-w <time>\tSet wall clock time limit (seconds, fractions allowed)\n\
+-x <time>\tSet extra timeout, before which a timing-out program is not yet killed,\n\
+\t\tso that its real execution time is reported (seconds, fractions allowed)\n\
");
exit(2);
}
int c;
uid_t uid;
- while ((c = getopt(argc, argv, "a:c:eE:fi:m:M:o:p:r:s:t:Tvw:")) >= 0)
+ while ((c = getopt(argc, argv, "a:c:eE:fi:m:M:o:p:r:s:t:Tvw:x:")) >= 0)
switch (c)
{
case 'a':
case 'w':
wall_timeout = 1000*atof(optarg);
break;
+ case 'x':
+ extra_timeout = 1000*atof(optarg);
+ break;
default:
usage();
}