]> mj.ucw.cz Git - moe.git/blob - box/box.c
0788ac4b51ec54b3484b054d5b9ac67bef42e06d
[moe.git] / box / box.c
1 /*
2  *      A Simple Sandbox for Moe
3  *
4  *      (c) 2001--2010 Martin Mares <mj@ucw.cz>
5  */
6
7 #define _LARGEFILE64_SOURCE
8 #define _GNU_SOURCE
9
10 #include "autoconf.h"
11
12 #include <errno.h>
13 #include <stdio.h>
14 #include <fcntl.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stdarg.h>
18 #include <stdint.h>
19 #include <unistd.h>
20 #include <getopt.h>
21 #include <time.h>
22 #include <sys/wait.h>
23 #include <sys/user.h>
24 #include <sys/time.h>
25 #include <sys/ptrace.h>
26 #include <sys/signal.h>
27 #include <sys/sysinfo.h>
28 #include <sys/resource.h>
29 #include <sys/utsname.h>
30 #include <linux/ptrace.h>
31
32 #if defined(CONFIG_BOX_KERNEL_AMD64) && !defined(CONFIG_BOX_USER_AMD64)
33 #include <asm/unistd_32.h>
34 #define NATIVE_NR_execve 59             /* 64-bit execve */
35 #else
36 #include <asm/unistd.h>
37 #define NATIVE_NR_execve __NR_execve
38 #endif
39
40 #define NONRET __attribute__((noreturn))
41 #define UNUSED __attribute__((unused))
42 #define ARRAY_SIZE(a) (int)(sizeof(a)/sizeof(a[0]))
43
44 static int filter_syscalls;             /* 0=off, 1=liberal, 2=totalitarian */
45 static int timeout;                     /* milliseconds */
46 static int wall_timeout;
47 static int extra_timeout;
48 static int pass_environ;
49 static int file_access;
50 static int verbose;
51 static int memory_limit;
52 static int stack_limit;
53 static char *redir_stdin, *redir_stdout, *redir_stderr;
54 static char *set_cwd;
55
56 static pid_t box_pid;
57 static int is_ptraced;
58 static volatile int timer_tick;
59 static struct timeval start_time;
60 static int ticks_per_sec;
61 static int exec_seen;
62 static int partial_line;
63
64 static int mem_peak_kb;
65 static int total_ms, wall_ms;
66
67 static void die(char *msg, ...) NONRET;
68 static void sample_mem_peak(void);
69
70 /*** Meta-files ***/
71
72 static FILE *metafile;
73
74 static void
75 meta_open(const char *name)
76 {
77   if (!strcmp(name, "-"))
78     {
79       metafile = stdout;
80       return;
81     }
82   metafile = fopen(name, "w");
83   if (!metafile)
84     die("Failed to open metafile '%s'",name);
85 }
86
87 static void
88 meta_close(void)
89 {
90   if (metafile && metafile != stdout)
91     fclose(metafile);
92 }
93
94 static void __attribute__((format(printf,1,2)))
95 meta_printf(const char *fmt, ...)
96 {
97   if (!metafile)
98     return;
99
100   va_list args;
101   va_start(args, fmt);
102   vfprintf(metafile, fmt, args);
103   va_end(args);
104 }
105
106 static void
107 final_stats(struct rusage *rus)
108 {
109   struct timeval total, now, wall;
110   timeradd(&rus->ru_utime, &rus->ru_stime, &total);
111   total_ms = total.tv_sec*1000 + total.tv_usec/1000;
112   gettimeofday(&now, NULL);
113   timersub(&now, &start_time, &wall);
114   wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000;
115
116   meta_printf("time:%d.%03d\n", total_ms/1000, total_ms%1000);
117   meta_printf("time-wall:%d.%03d\n", wall_ms/1000, wall_ms%1000);
118   meta_printf("mem:%llu\n", (unsigned long long) mem_peak_kb * 1024);
119 }
120
121 /*** Messages and exits ***/
122
123 static void NONRET
124 box_exit(int rc)
125 {
126   if (box_pid > 0)
127     {
128       sample_mem_peak();
129       if (is_ptraced)
130         ptrace(PTRACE_KILL, box_pid);
131       kill(-box_pid, SIGKILL);
132       kill(box_pid, SIGKILL);
133       meta_printf("killed:1\n");
134
135       struct rusage rus;
136       int p, stat;
137       do
138         p = wait4(box_pid, &stat, 0, &rus);
139       while (p < 0 && errno == EINTR);
140       if (p < 0)
141         fprintf(stderr, "UGH: Lost track of the process (%m)\n");
142       else
143         final_stats(&rus);
144     }
145   meta_close();
146   exit(rc);
147 }
148
149 static void
150 flush_line(void)
151 {
152   if (partial_line)
153     fputc('\n', stderr);
154   partial_line = 0;
155 }
156
157 /* Report an error of the sandbox itself */
158 static void NONRET __attribute__((format(printf,1,2)))
159 die(char *msg, ...)
160 {
161   va_list args;
162   va_start(args, msg);
163   flush_line();
164   char buf[1024];
165   vsnprintf(buf, sizeof(buf), msg, args);
166   meta_printf("status:XX\nmessage:%s\n", buf);
167   fputs(buf, stderr);
168   fputc('\n', stderr);
169   box_exit(2);
170 }
171
172 /* Report an error of the program inside the sandbox */
173 static void NONRET __attribute__((format(printf,1,2)))
174 err(char *msg, ...)
175 {
176   va_list args;
177   va_start(args, msg);
178   flush_line();
179   if (msg[0] && msg[1] && msg[2] == ':' && msg[3] == ' ')
180     {
181       meta_printf("status:%c%c\n", msg[0], msg[1]);
182       msg += 4;
183     }
184   char buf[1024];
185   vsnprintf(buf, sizeof(buf), msg, args);
186   meta_printf("message:%s\n", buf);
187   fputs(buf, stderr);
188   fputc('\n', stderr);
189   box_exit(1);
190 }
191
192 /* Write a message, but only if in verbose mode */
193 static void __attribute__((format(printf,1,2)))
194 msg(char *msg, ...)
195 {
196   va_list args;
197   va_start(args, msg);
198   if (verbose)
199     {
200       int len = strlen(msg);
201       if (len > 0)
202         partial_line = (msg[len-1] != '\n');
203       vfprintf(stderr, msg, args);
204       fflush(stderr);
205     }
206   va_end(args);
207 }
208
209 static void *
210 xmalloc(size_t size)
211 {
212   void *p = malloc(size);
213   if (!p)
214     die("Out of memory");
215   return p;
216 }
217
218 /*** Syscall rules ***/
219
220 static const char * const syscall_names[] = {
221 #include "box/syscall-table.h"
222 };
223 #define NUM_SYSCALLS ARRAY_SIZE(syscall_names)
224 #define NUM_ACTIONS (NUM_SYSCALLS+64)
225
226 enum action {
227   A_DEFAULT,            // Use the default action
228   A_NO,                 // Always forbid
229   A_YES,                // Always permit
230   A_FILENAME,           // Permit if arg1 is a known filename
231   A_ACTION_MASK = 15,
232   A_NO_RETVAL = 32,     // Does not return a value
233   A_SAMPLE_MEM = 64,    // Sample memory usage before the syscall
234   A_LIBERAL = 128,      // Valid only in liberal mode
235   // Must fit in a unsigned char
236 };
237
238 static unsigned char syscall_action[NUM_ACTIONS] = {
239 #define S(x) [__NR_##x]
240
241     // Syscalls permitted for specific file names
242     S(open) = A_FILENAME,
243     S(creat) = A_FILENAME,
244     S(unlink) = A_FILENAME,
245     S(access) = A_FILENAME,                     
246     S(truncate) = A_FILENAME,
247     S(stat) = A_FILENAME,
248     S(lstat) = A_FILENAME,
249     S(readlink) = A_FILENAME,
250 #ifndef CONFIG_BOX_USER_AMD64
251     S(oldstat) = A_FILENAME,
252     S(oldlstat) = A_FILENAME,
253     S(truncate64) = A_FILENAME,
254     S(stat64) = A_FILENAME,
255     S(lstat64) = A_FILENAME,
256 #endif
257
258     // Syscalls permitted always
259     S(exit) = A_YES | A_SAMPLE_MEM,
260     S(read) = A_YES,
261     S(write) = A_YES,
262     S(close) = A_YES,
263     S(lseek) = A_YES,
264     S(getpid) = A_YES,
265     S(getuid) = A_YES,
266     S(dup) = A_YES,
267     S(brk) = A_YES,
268     S(getgid) = A_YES,
269     S(geteuid) = A_YES,
270     S(getegid) = A_YES,
271     S(dup2) = A_YES,
272     S(ftruncate) = A_YES,
273     S(fstat) = A_YES,
274     S(personality) = A_YES,
275     S(readv) = A_YES,
276     S(writev) = A_YES,
277     S(getresuid) = A_YES,
278 #ifdef __NR_pread64
279     S(pread64) = A_YES,
280     S(pwrite64) = A_YES,
281 #else
282     S(pread) = A_YES,
283     S(pwrite) = A_YES,
284 #endif
285     S(fcntl) = A_YES,
286     S(mmap) = A_YES,
287     S(munmap) = A_YES,
288     S(ioctl) = A_YES,
289     S(uname) = A_YES,
290     S(gettid) = A_YES,
291     S(set_thread_area) = A_YES,
292     S(get_thread_area) = A_YES,
293     S(set_tid_address) = A_YES,
294     S(exit_group) = A_YES | A_SAMPLE_MEM,
295 #ifndef CONFIG_BOX_USER_AMD64
296     S(oldfstat) = A_YES,
297     S(ftruncate64) = A_YES,
298     S(_llseek) = A_YES,
299     S(fstat64) = A_YES,
300     S(fcntl64) = A_YES,
301     S(mmap2) = A_YES,
302 #endif
303
304     // Syscalls permitted only in liberal mode
305     S(time) = A_YES | A_LIBERAL,
306     S(alarm) = A_YES | A_LIBERAL,
307     S(pause) = A_YES | A_LIBERAL,
308     S(fchmod) = A_YES | A_LIBERAL,
309     S(getrlimit) = A_YES | A_LIBERAL,
310     S(getrusage) = A_YES | A_LIBERAL,
311     S(gettimeofday) = A_YES | A_LIBERAL,
312     S(select) = A_YES | A_LIBERAL,
313     S(setitimer) = A_YES | A_LIBERAL,
314     S(getitimer) = A_YES | A_LIBERAL,
315     S(mprotect) = A_YES | A_LIBERAL,
316     S(getdents) = A_YES | A_LIBERAL,
317     S(getdents64) = A_YES | A_LIBERAL,
318     S(fdatasync) = A_YES | A_LIBERAL,
319     S(mremap) = A_YES | A_LIBERAL,
320     S(poll) = A_YES | A_LIBERAL,
321     S(getcwd) = A_YES | A_LIBERAL,
322     S(nanosleep) = A_YES | A_LIBERAL,
323     S(rt_sigreturn) = A_YES | A_LIBERAL | A_NO_RETVAL,
324     S(rt_sigaction) = A_YES | A_LIBERAL,
325     S(rt_sigprocmask) = A_YES | A_LIBERAL,
326     S(rt_sigpending) = A_YES | A_LIBERAL,
327     S(rt_sigtimedwait) = A_YES | A_LIBERAL,
328     S(rt_sigqueueinfo) = A_YES | A_LIBERAL,
329     S(rt_sigsuspend) = A_YES | A_LIBERAL,
330     S(_sysctl) = A_YES | A_LIBERAL,
331 #ifndef CONFIG_BOX_USER_AMD64
332     S(sigaction) = A_YES | A_LIBERAL,
333     S(sgetmask) = A_YES | A_LIBERAL,
334     S(ssetmask) = A_YES | A_LIBERAL,
335     S(sigsuspend) = A_YES | A_LIBERAL,
336     S(sigpending) = A_YES | A_LIBERAL,
337     S(sigreturn) = A_YES | A_LIBERAL | A_NO_RETVAL,
338     S(sigprocmask) = A_YES | A_LIBERAL,
339     S(ugetrlimit) = A_YES | A_LIBERAL,
340     S(readdir) = A_YES | A_LIBERAL,
341     S(signal) = A_YES | A_LIBERAL,
342     S(_newselect) = A_YES | A_LIBERAL,
343 #endif
344
345 #undef S
346 };
347
348 static const char *
349 syscall_name(unsigned int id, char *buf)
350 {
351   if (id < NUM_SYSCALLS && syscall_names[id])
352     return syscall_names[id];
353   else
354     {
355       sprintf(buf, "#%d", id);
356       return buf;
357     }
358 }
359
360 static int
361 syscall_by_name(char *name)
362 {
363   for (unsigned int i=0; i<NUM_SYSCALLS; i++)
364     if (syscall_names[i] && !strcmp(syscall_names[i], name))
365       return i;
366   if (name[0] == '#')
367     name++;
368   if (!*name)
369     return -1;
370   char *ep;
371   unsigned long l = strtoul(name, &ep, 0);
372   if (*ep)
373     return -1;
374   if (l >= NUM_ACTIONS)
375     return NUM_ACTIONS;
376   return l;
377 }
378
379 static int
380 set_syscall_action(char *a)
381 {
382   char *sep = strchr(a, '=');
383   enum action act = A_YES;
384   if (sep)
385     {
386       *sep++ = 0;
387       if (!strcmp(sep, "yes"))
388         act = A_YES;
389       else if (!strcmp(sep, "no"))
390         act = A_NO;
391       else if (!strcmp(sep, "file"))
392         act = A_FILENAME;
393       else
394         return 0;
395     }
396
397   int sys = syscall_by_name(a);
398   if (sys < 0)
399     die("Unknown syscall `%s'", a);
400   if (sys >= NUM_ACTIONS)
401     die("Syscall `%s' out of range", a);
402   syscall_action[sys] = act;
403   return 1;
404 }
405
406 /*** Path rules ***/
407
408 struct path_rule {
409   char *path;
410   enum action action;
411   struct path_rule *next;
412 };
413
414 static struct path_rule default_path_rules[] = {
415   { "/etc/", A_YES },
416   { "/lib/", A_YES },
417   { "/usr/lib/", A_YES },
418   { "/opt/lib/", A_YES },
419   { "/usr/share/zoneinfo/", A_YES },
420   { "/usr/share/locale/", A_YES },
421   { "/dev/null", A_YES },
422   { "/dev/zero", A_YES },
423   { "/proc/meminfo", A_YES },
424   { "/proc/self/stat", A_YES },
425   { "/proc/self/exe", A_YES },                  // Needed by FPC 2.0.x runtime
426 };
427
428 static struct path_rule *user_path_rules;
429 static struct path_rule **last_path_rule = &user_path_rules;
430
431 static int
432 set_path_action(char *a)
433 {
434   char *sep = strchr(a, '=');
435   enum action act = A_YES;
436   if (sep)
437     {
438       *sep++ = 0;
439       if (!strcmp(sep, "yes"))
440         act = A_YES;
441       else if (!strcmp(sep, "no"))
442         act = A_NO;
443       else
444         return 0;
445     }
446
447   struct path_rule *r = xmalloc(sizeof(*r) + strlen(a) + 1);
448   r->path = (char *)(r+1);
449   strcpy(r->path, a);
450   r->action = act;
451   r->next = NULL;
452   *last_path_rule = r;
453   last_path_rule = &r->next;
454   return 1;
455 }
456
457 static enum action
458 match_path_rule(struct path_rule *r, char *path)
459 {
460   char *rr = r->path;
461   while (*rr)
462     if (*rr++ != *path++)
463       {
464         if (rr[-1] == '/' && !path[-1])
465           break;
466         return A_DEFAULT;
467       }
468   if (rr > r->path && rr[-1] != '/' && *path)
469     return A_DEFAULT;
470   return r->action;
471 }
472
473 /*** Environment rules ***/
474
475 struct env_rule {
476   char *var;                    // Variable to match
477   char *val;                    // ""=clear, NULL=inherit
478   int var_len;
479   struct env_rule *next;
480 };
481
482 static struct env_rule *first_env_rule;
483 static struct env_rule **last_env_rule = &first_env_rule;
484
485 static struct env_rule default_env_rules[] = {
486   { "LIBC_FATAL_STDERR_", "1" }
487 };
488
489 static int
490 set_env_action(char *a0)
491 {
492   struct env_rule *r = xmalloc(sizeof(*r) + strlen(a0) + 1);
493   char *a = (char *)(r+1);
494   strcpy(a, a0);
495
496   char *sep = strchr(a, '=');
497   if (sep == a)
498     return 0;
499   r->var = a;
500   if (sep)
501     {
502       *sep++ = 0;
503       r->val = sep;
504     }
505   else
506     r->val = NULL;
507   *last_env_rule = r;
508   last_env_rule = &r->next;
509   r->next = NULL;
510   return 1;
511 }
512
513 static int
514 match_env_var(char *env_entry, struct env_rule *r)
515 {
516   if (strncmp(env_entry, r->var, r->var_len))
517     return 0;
518   return (env_entry[r->var_len] == '=');
519 }
520
521 static void
522 apply_env_rule(char **env, int *env_sizep, struct env_rule *r)
523 {
524   // First remove the variable if already set
525   int pos = 0;
526   while (pos < *env_sizep && !match_env_var(env[pos], r))
527     pos++;
528   if (pos < *env_sizep)
529     {
530       (*env_sizep)--;
531       env[pos] = env[*env_sizep];
532       env[*env_sizep] = NULL;
533     }
534
535   // What is the new value?
536   char *new;
537   if (r->val)
538     {
539       if (!r->val[0])
540         return;
541       new = xmalloc(r->var_len + 1 + strlen(r->val) + 1);
542       sprintf(new, "%s=%s", r->var, r->val);
543     }
544   else
545     {
546       pos = 0;
547       while (environ[pos] && !match_env_var(environ[pos], r))
548         pos++;
549       if (!(new = environ[pos]))
550         return;
551     }
552
553   // Add it at the end of the array
554   env[(*env_sizep)++] = new;
555   env[*env_sizep] = NULL;
556 }
557
558 static char **
559 setup_environment(void)
560 {
561   // Link built-in rules with user rules
562   for (int i=ARRAY_SIZE(default_env_rules)-1; i >= 0; i--)
563     {
564       default_env_rules[i].next = first_env_rule;
565       first_env_rule = &default_env_rules[i];
566     }
567
568   // Scan the original environment
569   char **orig_env = environ;
570   int orig_size = 0;
571   while (orig_env[orig_size])
572     orig_size++;
573
574   // For each rule, reserve one more slot and calculate length
575   int num_rules = 0;
576   for (struct env_rule *r = first_env_rule; r; r=r->next)
577     {
578       num_rules++;
579       r->var_len = strlen(r->var);
580     }
581
582   // Create a new environment
583   char **env = xmalloc((orig_size + num_rules + 1) * sizeof(char *));
584   int size;
585   if (pass_environ)
586     {
587       memcpy(env, environ, orig_size * sizeof(char *));
588       size = orig_size;
589     }
590   else
591     size = 0;
592   env[size] = NULL;
593
594   // Apply the rules one by one
595   for (struct env_rule *r = first_env_rule; r; r=r->next)
596     apply_env_rule(env, &size, r);
597
598   // Return the new env and pass some gossip
599   if (verbose > 1)
600     {
601       fprintf(stderr, "Passing environment:\n");
602       for (int i=0; env[i]; i++)
603         fprintf(stderr, "\t%s\n", env[i]);
604     }
605   return env;
606 }
607
608 /*** Low-level parsing of syscalls ***/
609
610 #ifdef CONFIG_BOX_KERNEL_AMD64
611 typedef uint64_t arg_t;
612 #else
613 typedef uint32_t arg_t;
614 #endif
615
616 struct syscall_args {
617   arg_t sys;
618   arg_t arg1, arg2, arg3;
619   arg_t result;
620   struct user user;
621 };
622
623 static int read_user_mem(arg_t addr, char *buf, int len)
624 {
625   static int mem_fd;
626
627   if (!mem_fd)
628     {
629       char memname[64];
630       sprintf(memname, "/proc/%d/mem", (int) box_pid);
631       mem_fd = open(memname, O_RDONLY);
632       if (mem_fd < 0)
633         die("open(%s): %m", memname);
634     }
635   if (lseek64(mem_fd, addr, SEEK_SET) < 0)
636     die("lseek64(mem): %m");
637   return read(mem_fd, buf, len);
638 }
639
640 #ifdef CONFIG_BOX_KERNEL_AMD64
641
642 static void
643 get_syscall_args(struct syscall_args *a, int is_exit)
644 {
645   if (ptrace(PTRACE_GETREGS, box_pid, NULL, &a->user) < 0)
646     die("ptrace(PTRACE_GETREGS): %m");
647   a->sys = a->user.regs.orig_rax;
648   a->result = a->user.regs.rax;
649
650   /*
651    *  CAVEAT: We have to check carefully that this is a real 64-bit syscall.
652    *  We test whether the process runs in 64-bit mode, but surprisingly this
653    *  is not enough: a 64-bit process can still issue the INT 0x80 instruction
654    *  which performs a 32-bit syscall. Currently, the only known way how to
655    *  detect this situation is to inspect the instruction code (the kernel
656    *  keeps a syscall type flag internally, but it is not accessible from
657    *  user space). Hopefully, there is no instruction whose suffix is the
658    *  code of the SYSCALL instruction. Sometimes, one would wish the
659    *  instruction codes to be unique even when read backwards :)
660    */
661
662   if (is_exit)
663     return;
664
665   int sys_type;
666   uint16_t instr;
667
668   switch (a->user.regs.cs)
669     {
670     case 0x23:
671       // 32-bit CPU mode => only 32-bit syscalls can be issued
672       sys_type = 32;
673       break;
674     case 0x33:
675       // 64-bit CPU mode
676       if (read_user_mem(a->user.regs.rip-2, (char *) &instr, 2) != 2)
677         err("FO: Cannot read syscall instruction");
678       switch (instr)
679         {
680         case 0x050f:
681           break;
682         case 0x80cd:
683           err("FO: Forbidden 32-bit syscall in 64-bit mode");
684         default:
685           err("XX: Unknown syscall instruction %04x", instr);
686         }
687       sys_type = 64;
688       break;
689     default:
690       err("XX: Unknown code segment %04jx", (intmax_t) a->user.regs.cs);
691     }
692
693 #ifdef CONFIG_BOX_USER_AMD64
694   if (sys_type != 64)
695     err("FO: Forbidden %d-bit mode syscall", sys_type);
696 #else
697   if (sys_type != (exec_seen ? 32 : 64))
698     err("FO: Forbidden %d-bit mode syscall", sys_type);
699 #endif
700
701   if (sys_type == 32)
702     {
703       a->arg1 = a->user.regs.rbx;
704       a->arg2 = a->user.regs.rcx;
705       a->arg3 = a->user.regs.rdx;
706     }
707   else
708     {
709       a->arg1 = a->user.regs.rdi;
710       a->arg2 = a->user.regs.rsi;
711       a->arg3 = a->user.regs.rdx;
712     }
713 }
714
715 static void
716 set_syscall_nr(struct syscall_args *a, arg_t sys)
717 {
718   a->sys = sys;
719   a->user.regs.orig_rax = sys;
720   if (ptrace(PTRACE_SETREGS, box_pid, NULL, &a->user) < 0)
721     die("ptrace(PTRACE_SETREGS): %m");
722 }
723
724 static void
725 sanity_check(void)
726 {
727 }
728
729 #else
730
731 static void
732 get_syscall_args(struct syscall_args *a, int is_exit UNUSED)
733 {
734   if (ptrace(PTRACE_GETREGS, box_pid, NULL, &a->user) < 0)
735     die("ptrace(PTRACE_GETREGS): %m");
736   a->sys = a->user.regs.orig_eax;
737   a->arg1 = a->user.regs.ebx;
738   a->arg2 = a->user.regs.ecx;
739   a->arg3 = a->user.regs.edx;
740   a->result = a->user.regs.eax;
741 }
742
743 static void
744 set_syscall_nr(struct syscall_args *a, arg_t sys)
745 {
746   a->sys = sys;
747   a->user.regs.orig_eax = sys;
748   if (ptrace(PTRACE_SETREGS, box_pid, NULL, &a->user) < 0)
749     die("ptrace(PTRACE_SETREGS): %m");
750 }
751
752 static void
753 sanity_check(void)
754 {
755 #if !defined(CONFIG_BOX_ALLOW_INSECURE)
756   struct utsname uts;
757   if (uname(&uts) < 0)
758     die("uname() failed: %m");
759
760   if (!strcmp(uts.machine, "x86_64"))
761     die("Running 32-bit sandbox on 64-bit kernels is inherently unsafe. Please get a 64-bit version.");
762 #endif
763 }
764
765 #endif
766
767 /*** Syscall checks ***/
768
769 static void
770 valid_filename(arg_t addr)
771 {
772   char namebuf[4096], *p, *end;
773
774   if (!file_access)
775     err("FA: File access forbidden");
776   if (file_access >= 9)
777     return;
778
779   p = end = namebuf;
780   do
781     {
782       if (p >= end)
783         {
784           int remains = PAGE_SIZE - (addr & (PAGE_SIZE-1));
785           int l = namebuf + sizeof(namebuf) - end;
786           if (l > remains)
787             l = remains;
788           if (!l)
789             err("FA: Access to file with name too long");
790           remains = read_user_mem(addr, end, l);
791           if (remains < 0)
792             die("read(mem): %m");
793           if (!remains)
794             err("FA: Access to file with name out of memory");
795           end += remains;
796           addr += remains;
797         }
798     }
799   while (*p++);
800
801   msg("[%s] ", namebuf);
802   if (file_access >= 3)
803     return;
804
805   // Everything in current directory is permitted
806   if (!strchr(namebuf, '/') && strcmp(namebuf, ".."))
807     return;
808
809   // ".." anywhere in the path is forbidden
810   enum action act = A_DEFAULT;
811   if (strstr(namebuf, ".."))
812     act = A_NO;
813
814   // Scan user rules
815   for (struct path_rule *r = user_path_rules; r && !act; r=r->next)
816     act = match_path_rule(r, namebuf);
817
818   // Scan built-in rules
819   if (file_access >= 2)
820     for (int i=0; i<ARRAY_SIZE(default_path_rules) && !act; i++)
821       act = match_path_rule(&default_path_rules[i], namebuf);
822
823   if (act != A_YES)
824     err("FA: Forbidden access to file `%s'", namebuf);
825 }
826
827 // Check syscall. If invalid, return -1, otherwise return the action mask.
828 static int
829 valid_syscall(struct syscall_args *a)
830 {
831   unsigned int sys = a->sys;
832   unsigned int act = (sys < NUM_ACTIONS) ? syscall_action[sys] : A_DEFAULT;
833
834   if (act & A_LIBERAL)
835     {
836       if (filter_syscalls != 1)
837         act = A_DEFAULT;
838     }
839
840   switch (act & A_ACTION_MASK)
841     {
842     case A_YES:
843       return act;
844     case A_NO:
845       return -1;
846     case A_FILENAME:
847       valid_filename(a->arg1);
848       return act;
849     default: ;
850     }
851
852   switch (sys)
853     {
854     case __NR_kill:
855       if (a->arg1 == (arg_t) box_pid)
856         {
857           meta_printf("exitsig:%d\n", (int) a->arg2);
858           err("SG: Committed suicide by signal %d", (int) a->arg2);
859         }
860       return -1;
861     case __NR_tgkill:
862       if (a->arg1 == (arg_t) box_pid && a->arg2 == (arg_t) box_pid)
863         {
864           meta_printf("exitsig:%d\n", (int) a->arg3);
865           err("SG: Committed suicide by signal %d", (int) a->arg3);
866         }
867       return -1;
868     default:
869       return -1;
870     }
871 }
872
873 static void
874 signal_alarm(int unused UNUSED)
875 {
876   /* Time limit checks are synchronous, so we only schedule them there. */
877   timer_tick = 1;
878   alarm(1);
879 }
880
881 static void
882 signal_int(int unused UNUSED)
883 {
884   /* Interrupts are fatal, so no synchronization requirements. */
885   meta_printf("exitsig:%d\n", SIGINT);
886   err("SG: Interrupted");
887 }
888
889 #define PROC_BUF_SIZE 4096
890 static void
891 read_proc_file(char *buf, char *name, int *fdp)
892 {
893   int c;
894
895   if (!*fdp)
896     {
897       sprintf(buf, "/proc/%d/%s", (int) box_pid, name);
898       *fdp = open(buf, O_RDONLY);
899       if (*fdp < 0)
900         die("open(%s): %m", buf);
901     }
902   lseek(*fdp, 0, SEEK_SET);
903   if ((c = read(*fdp, buf, PROC_BUF_SIZE-1)) < 0)
904     die("read on /proc/$pid/%s: %m", name);
905   if (c >= PROC_BUF_SIZE-1)
906     die("/proc/$pid/%s too long", name);
907   buf[c] = 0;
908 }
909
910 static void
911 check_timeout(void)
912 {
913   if (wall_timeout)
914     {
915       struct timeval now, wall;
916       int wall_ms;
917       gettimeofday(&now, NULL);
918       timersub(&now, &start_time, &wall);
919       wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000;
920       if (wall_ms > wall_timeout)
921         err("TO: Time limit exceeded (wall clock)");
922       if (verbose > 1)
923         fprintf(stderr, "[wall time check: %d msec]\n", wall_ms);
924     }
925   if (timeout)
926     {
927       char buf[PROC_BUF_SIZE], *x;
928       int utime, stime, ms;
929       static int proc_stat_fd;
930       read_proc_file(buf, "stat", &proc_stat_fd);
931       x = buf;
932       while (*x && *x != ' ')
933         x++;
934       while (*x == ' ')
935         x++;
936       if (*x++ != '(')
937         die("proc stat syntax error 1");
938       while (*x && (*x != ')' || x[1] != ' '))
939         x++;
940       while (*x == ')' || *x == ' ')
941         x++;
942       if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
943         die("proc stat syntax error 2");
944       ms = (utime + stime) * 1000 / ticks_per_sec;
945       if (verbose > 1)
946         fprintf(stderr, "[time check: %d msec]\n", ms);
947       if (ms > timeout && ms > extra_timeout)
948         err("TO: Time limit exceeded");
949     }
950 }
951
952 static void
953 sample_mem_peak(void)
954 {
955   /*
956    *  We want to find out the peak memory usage of the process, which is
957    *  maintained by the kernel, but unforunately it gets lost when the
958    *  process exits (it is not reported in struct rusage). Therefore we
959    *  have to sample it whenever we suspect that the process is about
960    *  to exit.
961    */
962   char buf[PROC_BUF_SIZE], *x;
963   static int proc_status_fd;
964   read_proc_file(buf, "status", &proc_status_fd);
965
966   x = buf;
967   while (*x)
968     {
969       char *key = x;
970       while (*x && *x != ':' && *x != '\n')
971         x++;
972       if (!*x || *x == '\n')
973         break;
974       *x++ = 0;
975       while (*x == ' ' || *x == '\t')
976         x++;
977
978       char *val = x;
979       while (*x && *x != '\n')
980         x++;
981       if (!*x)
982         break;
983       *x++ = 0;
984
985       if (!strcmp(key, "VmPeak"))
986         {
987           int peak = atoi(val);
988           if (peak > mem_peak_kb)
989             mem_peak_kb = peak;
990         }
991     }
992
993   if (verbose > 1)
994     msg("[mem-peak: %u KB]\n", mem_peak_kb);
995 }
996
997 static void
998 boxkeeper(void)
999 {
1000   int syscall_count = (filter_syscalls ? 0 : 1);
1001   struct sigaction sa;
1002
1003   is_ptraced = 1;
1004
1005   bzero(&sa, sizeof(sa));
1006   sa.sa_handler = signal_int;
1007   sigaction(SIGINT, &sa, NULL);
1008
1009   gettimeofday(&start_time, NULL);
1010   ticks_per_sec = sysconf(_SC_CLK_TCK);
1011   if (ticks_per_sec <= 0)
1012     die("Invalid ticks_per_sec!");
1013
1014   if (timeout || wall_timeout)
1015     {
1016       sa.sa_handler = signal_alarm;
1017       sigaction(SIGALRM, &sa, NULL);
1018       alarm(1);
1019     }
1020
1021   for(;;)
1022     {
1023       struct rusage rus;
1024       int stat;
1025       pid_t p;
1026       if (timer_tick)
1027         {
1028           check_timeout();
1029           timer_tick = 0;
1030         }
1031       p = wait4(box_pid, &stat, WUNTRACED, &rus);
1032       if (p < 0)
1033         {
1034           if (errno == EINTR)
1035             continue;
1036           die("wait4: %m");
1037         }
1038       if (p != box_pid)
1039         die("wait4: unknown pid %d exited!", p);
1040       if (WIFEXITED(stat))
1041         {
1042           box_pid = 0;
1043           final_stats(&rus);
1044           if (WEXITSTATUS(stat))
1045             {
1046               if (syscall_count)
1047                 {
1048                   meta_printf("exitcode:%d\n", WEXITSTATUS(stat));
1049                   err("RE: Exited with error status %d", WEXITSTATUS(stat));
1050                 }
1051               else
1052                 {
1053                   // Internal error happened inside the child process and it has been already reported.
1054                   box_exit(2);
1055                 }
1056             }
1057           if (timeout && total_ms > timeout)
1058             err("TO: Time limit exceeded");
1059           if (wall_timeout && wall_ms > wall_timeout)
1060             err("TO: Time limit exceeded (wall clock)");
1061           flush_line();
1062           fprintf(stderr, "OK (%d.%03d sec real, %d.%03d sec wall, %d MB, %d syscalls)\n",
1063               total_ms/1000, total_ms%1000,
1064               wall_ms/1000, wall_ms%1000,
1065               (mem_peak_kb + 1023) / 1024,
1066               syscall_count);
1067           box_exit(0);
1068         }
1069       if (WIFSIGNALED(stat))
1070         {
1071           box_pid = 0;
1072           meta_printf("exitsig:%d\n", WTERMSIG(stat));
1073           final_stats(&rus);
1074           err("SG: Caught fatal signal %d%s", WTERMSIG(stat), (syscall_count ? "" : " during startup"));
1075         }
1076       if (WIFSTOPPED(stat))
1077         {
1078           int sig = WSTOPSIG(stat);
1079           if (sig == SIGTRAP)
1080             {
1081               if (verbose > 2)
1082                 msg("[ptrace status %08x] ", stat);
1083               static int stop_count;
1084               if (!stop_count++)                /* Traceme request */
1085                 msg(">> Traceme request caught\n");
1086               else
1087                 err("SG: Breakpoint");
1088               ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1089             }
1090           else if (sig == (SIGTRAP | 0x80))
1091             {
1092               if (verbose > 2)
1093                 msg("[ptrace status %08x] ", stat);
1094               struct syscall_args a;
1095               static unsigned int sys_tick, last_act;
1096               static arg_t last_sys;
1097               if (++sys_tick & 1)               /* Syscall entry */
1098                 {
1099                   char namebuf[32];
1100                   int act;
1101
1102                   get_syscall_args(&a, 0);
1103                   arg_t sys = a.sys;
1104                   msg(">> Syscall %-12s (%08jx,%08jx,%08jx) ", syscall_name(sys, namebuf), (intmax_t) a.arg1, (intmax_t) a.arg2, (intmax_t) a.arg3);
1105                   if (!exec_seen)
1106                     {
1107                       msg("[master] ");
1108                       if (sys == NATIVE_NR_execve)
1109                         exec_seen = 1;
1110                     }
1111                   else if ((act = valid_syscall(&a)) >= 0)
1112                     {
1113                       last_act = act;
1114                       syscall_count++;
1115                       if (act & A_SAMPLE_MEM)
1116                         sample_mem_peak();
1117                     }
1118                   else
1119                     {
1120                       /*
1121                        * Unfortunately, PTRACE_KILL kills _after_ the syscall completes,
1122                        * so we have to change it to something harmless (e.g., an undefined
1123                        * syscall) and make the program continue.
1124                        */
1125                       set_syscall_nr(&a, ~(arg_t)0);
1126                       err("FO: Forbidden syscall %s", syscall_name(sys, namebuf));
1127                     }
1128                   last_sys = sys;
1129                 }
1130               else                                      /* Syscall return */
1131                 {
1132                   get_syscall_args(&a, 1);
1133                   if (a.sys == ~(arg_t)0)
1134                     {
1135                       /* Some syscalls (sigreturn et al.) do not return a value */
1136                       if (!(last_act & A_NO_RETVAL))
1137                         err("XX: Syscall does not return, but it should");
1138                     }
1139                   else
1140                     {
1141                       if (a.sys != last_sys)
1142                         err("XX: Mismatched syscall entry/exit");
1143                     }
1144                   if (last_act & A_NO_RETVAL)
1145                     msg("= ?\n");
1146                   else
1147                     msg("= %jd\n", (intmax_t) a.result);
1148                 }
1149               ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1150             }
1151           else if (sig == SIGSTOP)
1152             {
1153               msg(">> SIGSTOP\n");
1154               if (ptrace(PTRACE_SETOPTIONS, box_pid, NULL, (void *) PTRACE_O_TRACESYSGOOD) < 0)
1155                 die("ptrace(PTRACE_SETOPTIONS): %m");
1156               ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1157             }
1158           else if (sig != SIGXCPU && sig != SIGXFSZ)
1159             {
1160               msg(">> Signal %d\n", sig);
1161               sample_mem_peak();                        /* Signal might be fatal, so update mem-peak */
1162               ptrace(PTRACE_SYSCALL, box_pid, 0, sig);
1163             }
1164           else
1165             {
1166               meta_printf("exitsig:%d", sig);
1167               err("SG: Received signal %d", sig);
1168             }
1169         }
1170       else
1171         die("wait4: unknown status %x, giving up!", stat);
1172     }
1173 }
1174
1175 static void
1176 box_inside(int argc, char **argv)
1177 {
1178   struct rlimit rl;
1179   char *args[argc+1];
1180
1181   memcpy(args, argv, argc * sizeof(char *));
1182   args[argc] = NULL;
1183   if (set_cwd && chdir(set_cwd))
1184     die("chdir: %m");
1185   if (redir_stdin)
1186     {
1187       close(0);
1188       if (open(redir_stdin, O_RDONLY) != 0)
1189         die("open(\"%s\"): %m", redir_stdin);
1190     }
1191   if (redir_stdout)
1192     {
1193       close(1);
1194       if (open(redir_stdout, O_WRONLY | O_CREAT | O_TRUNC, 0666) != 1)
1195         die("open(\"%s\"): %m", redir_stdout);
1196     }
1197   if (redir_stderr)
1198     {
1199       close(2);
1200       if (open(redir_stderr, O_WRONLY | O_CREAT | O_TRUNC, 0666) != 2)
1201         die("open(\"%s\"): %m", redir_stderr);
1202     }
1203   else
1204     dup2(1, 2);
1205   setpgrp();
1206
1207   if (memory_limit)
1208     {
1209       rl.rlim_cur = rl.rlim_max = memory_limit * 1024;
1210       if (setrlimit(RLIMIT_AS, &rl) < 0)
1211         die("setrlimit(RLIMIT_AS): %m");
1212     }
1213
1214   rl.rlim_cur = rl.rlim_max = (stack_limit ? (rlim_t)stack_limit * 1024 : RLIM_INFINITY);
1215   if (setrlimit(RLIMIT_STACK, &rl) < 0)
1216     die("setrlimit(RLIMIT_STACK): %m");
1217
1218   rl.rlim_cur = rl.rlim_max = 64;
1219   if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
1220     die("setrlimit(RLIMIT_NOFILE): %m");
1221
1222   char **env = setup_environment();
1223   if (filter_syscalls)
1224     {
1225       if (ptrace(PTRACE_TRACEME) < 0)
1226         die("ptrace(PTRACE_TRACEME): %m");
1227       /* Trick: Make sure that we are stopped until the boxkeeper wakes up. */
1228       raise(SIGSTOP);
1229     }
1230   execve(args[0], args, env);
1231   die("execve(\"%s\"): %m", args[0]);
1232 }
1233
1234 static void
1235 usage(void)
1236 {
1237   fprintf(stderr, "Invalid arguments!\n");
1238   printf("\
1239 Usage: box [<options>] -- <command> <arguments>\n\
1240 \n\
1241 Options:\n\
1242 -a <level>\tSet file access level (0=none, 1=cwd, 2=/etc,/lib,..., 3=whole fs, 9=no checks; needs -f)\n\
1243 -c <dir>\tChange directory to <dir> first\n\
1244 -e\t\tInherit full environment of the parent process\n\
1245 -E <var>\tInherit the environment variable <var> from the parent process\n\
1246 -E <var>=<val>\tSet the environment variable <var> to <val>; unset it if <var> is empty\n\
1247 -f\t\tFilter system calls (-ff=very restricted)\n\
1248 -i <file>\tRedirect stdin from <file>\n\
1249 -k <size>\tLimit stack size to <size> KB (default: 0=unlimited)\n\
1250 -m <size>\tLimit address space to <size> KB\n\
1251 -M <file>\tOutput process information to <file> (name:value)\n\
1252 -o <file>\tRedirect stdout to <file>\n\
1253 -p <path>\tPermit access to the specified path (or subtree if it ends with a `/')\n\
1254 -p <path>=<act>\tDefine action for the specified path (<act>=yes/no)\n\
1255 -r <file>\tRedirect stderr to <file>\n\
1256 -s <sys>\tPermit the specified syscall (be careful)\n\
1257 -s <sys>=<act>\tDefine action for the specified syscall (<act>=yes/no/file)\n\
1258 -t <time>\tSet run time limit (seconds, fractions allowed)\n\
1259 -T\t\tAllow syscalls for measuring run time\n\
1260 -v\t\tBe verbose (use multiple times for even more verbosity)\n\
1261 -w <time>\tSet wall clock time limit (seconds, fractions allowed)\n\
1262 -x <time>\tSet extra timeout, before which a timing-out program is not yet killed,\n\
1263 \t\tso that its real execution time is reported (seconds, fractions allowed)\n\
1264 ");
1265   exit(2);
1266 }
1267
1268 int
1269 main(int argc, char **argv)
1270 {
1271   int c;
1272   uid_t uid;
1273
1274   while ((c = getopt(argc, argv, "a:c:eE:fi:k:m:M:o:p:r:s:t:Tvw:x:")) >= 0)
1275     switch (c)
1276       {
1277       case 'a':
1278         file_access = atol(optarg);
1279         break;
1280       case 'c':
1281         set_cwd = optarg;
1282         break;
1283       case 'e':
1284         pass_environ = 1;
1285         break;
1286       case 'E':
1287         if (!set_env_action(optarg))
1288           usage();
1289         break;
1290       case 'f':
1291         filter_syscalls++;
1292         break;
1293       case 'k':
1294         stack_limit = atol(optarg);
1295         break;
1296       case 'i':
1297         redir_stdin = optarg;
1298         break;
1299       case 'm':
1300         memory_limit = atol(optarg);
1301         break;
1302       case 'M':
1303         meta_open(optarg);
1304         break;
1305       case 'o':
1306         redir_stdout = optarg;
1307         break;
1308       case 'p':
1309         if (!set_path_action(optarg))
1310           usage();
1311         break;
1312       case 'r':
1313         redir_stderr = optarg;
1314         break;
1315       case 's':
1316         if (!set_syscall_action(optarg))
1317           usage();
1318         break;
1319       case 't':
1320         timeout = 1000*atof(optarg);
1321         break;
1322       case 'T':
1323         syscall_action[__NR_times] = A_YES;
1324         break;
1325       case 'v':
1326         verbose++;
1327         break;
1328       case 'w':
1329         wall_timeout = 1000*atof(optarg);
1330         break;
1331       case 'x':
1332         extra_timeout = 1000*atof(optarg);
1333         break;
1334       default:
1335         usage();
1336       }
1337   if (optind >= argc)
1338     usage();
1339
1340   sanity_check();
1341   uid = geteuid();
1342   if (setreuid(uid, uid) < 0)
1343     die("setreuid: %m");
1344   box_pid = fork();
1345   if (box_pid < 0)
1346     die("fork: %m");
1347   if (!box_pid)
1348     box_inside(argc-optind, argv+optind);
1349   else
1350     boxkeeper();
1351   die("Internal error: fell over edge of the world");
1352 }