Description:
Merge pull request #8 from nattee/master add a new modified 64bit sandbox "box"
Commit status:
[Not Reviewed]
References:
merge default
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r201:9b414977da63 - - 1 file changed: 1760 inserted, 0 deleted

This diff has been collapsed as it changes many lines, (1760 lines changed) Show them Hide them
@@ -0,0 +1,1760
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 + /* Generated automatically by ./configure, please don't touch manually. */
11 + #define CONFIG_BOX_KERNEL_AMD64 1
12 + #define CONFIG_BOX_USER_AMD64 1
13 + #define CONFIG_DIR "cf"
14 + #define CONFIG_DIRECT_IO 1
15 + #define CONFIG_ISOLATE_BOX_DIR "/tmp/box"
16 + #define CONFIG_ISOLATE_CGROUP_ROOT "/sys/fs/cgroup"
17 + #define CONFIG_ISOLATE_FIRST_GID 60000
18 + #define CONFIG_ISOLATE_FIRST_UID 60000
19 + #define CONFIG_ISOLATE_NUM_BOXES 100
20 + #define CONFIG_LARGE_FILES 1
21 + #define CONFIG_LFS 1
22 + #define CONFIG_LINUX 1
23 + #define CONFIG_LOCAL 1
24 + #define CONFIG_UCW_PARTMAP_IS_MMAP 1
25 + #define CONFIG_UCW_PERL 1
26 + #define CONFIG_UCW_POOL_IS_MMAP 1
27 + #define CONFIG_UCW_RADIX_SORTER_BITS 10
28 + #define CONFIG_UCW_SHELL_UTILS 1
29 + #define CPU_64BIT_POINTERS 1
30 + #define CPU_ALLOW_UNALIGNED 1
31 + #define CPU_AMD64 1
32 + #define CPU_ARCH "default"
33 + #define CPU_LITTLE_ENDIAN 1
34 + #define CPU_PAGE_SIZE 4096
35 + #define CPU_STRUCT_ALIGN 8
36 + #define CWARNS_OFF " -Wno-pointer-sign"
37 + #define HAVE_ASCII_DOC "none"
38 + #define INSTALL_BIN_DIR "bin"
39 + #define INSTALL_CONFIG_DIR "cf"
40 + #define INSTALL_DOC_DIR "share/doc"
41 + #define INSTALL_INCLUDE_DIR "include"
42 + #define INSTALL_LIB_DIR "lib"
43 + #define INSTALL_LOG_DIR "log"
44 + #define INSTALL_MAN_DIR "share/man"
45 + #define INSTALL_PERL_DIR "lib/perl5"
46 + #define INSTALL_PKGCONFIG_DIR "lib/pkgconfig"
47 + #define INSTALL_PREFIX
48 + #define INSTALL_RUN_DIR "run"
49 + #define INSTALL_SBIN_DIR "sbin"
50 + #define INSTALL_SHARE_DIR "share"
51 + #define INSTALL_STATE_DIR "lib"
52 + #define INSTALL_USR_PREFIX
53 + #define INSTALL_VAR_PREFIX
54 + #define SHERLOCK_VERSION "3.99.2"
55 + #define SHERLOCK_VERSION_CODE 3099002
56 + #define SONAME_PREFIX "lib/"
57 + #define UCW_VERSION "3.99.2"
58 + #define UCW_VERSION_CODE 3099002
59 +
60 + #include <errno.h>
61 + #include <stdio.h>
62 + #include <fcntl.h>
63 + #include <stdlib.h>
64 + #include <string.h>
65 + #include <stdarg.h>
66 + #include <stdint.h>
67 + #include <unistd.h>
68 + #include <getopt.h>
69 + #include <time.h>
70 + #include <sys/wait.h>
71 + #include <sys/user.h>
72 + #include <sys/time.h>
73 + #include <sys/ptrace.h>
74 + #include <sys/signal.h>
75 + #include <sys/sysinfo.h>
76 + #include <sys/resource.h>
77 + #include <sys/utsname.h>
78 + //#include <linux/ptrace.h>
79 +
80 + #if defined(CONFIG_BOX_KERNEL_AMD64) && !defined(CONFIG_BOX_USER_AMD64)
81 + #include <asm/unistd_32.h>
82 + #define NATIVE_NR_execve 59 /* 64-bit execve */
83 + #else
84 + #include <asm/unistd.h>
85 + #define NATIVE_NR_execve __NR_execve
86 + #endif
87 +
88 + #define NONRET __attribute__((noreturn))
89 + #define UNUSED __attribute__((unused))
90 + #define ARRAY_SIZE(a) (int)(sizeof(a)/sizeof(a[0]))
91 +
92 + static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */
93 + static int timeout; /* milliseconds */
94 + static int wall_timeout;
95 + static int extra_timeout;
96 + static int pass_environ;
97 + static int file_access;
98 + static int verbose;
99 + static int memory_limit;
100 + static int stack_limit;
101 + static char *redir_stdin, *redir_stdout, *redir_stderr;
102 + static char *set_cwd;
103 +
104 + static pid_t box_pid;
105 + static int is_ptraced;
106 + static volatile int timer_tick;
107 + static struct timeval start_time;
108 + static int ticks_per_sec;
109 + static int exec_seen;
110 + static int partial_line;
111 +
112 + static int mem_peak_kb;
113 + static int total_ms, wall_ms, sys_ms;
114 +
115 + static void die(char *msg, ...) NONRET;
116 + static void sample_mem_peak(void);
117 +
118 + /*** Meta-files ***/
119 +
120 + static FILE *metafile;
121 +
122 + static void
123 + meta_open(const char *name)
124 + {
125 + if (!strcmp(name, "-"))
126 + {
127 + metafile = stdout;
128 + return;
129 + }
130 + metafile = fopen(name, "w");
131 + if (!metafile)
132 + die("Failed to open metafile '%s'",name);
133 + }
134 +
135 + static void
136 + meta_close(void)
137 + {
138 + if (metafile && metafile != stdout)
139 + fclose(metafile);
140 + }
141 +
142 + static void __attribute__((format(printf,1,2)))
143 + meta_printf(const char *fmt, ...)
144 + {
145 + if (!metafile)
146 + return;
147 +
148 + va_list args;
149 + va_start(args, fmt);
150 + vfprintf(metafile, fmt, args);
151 + va_end(args);
152 + }
153 +
154 +
155 + static void print_running_stat(double wall_time,
156 + double user_time,
157 + double system_time,
158 + int mem_usage)
159 + {
160 + //total is user
161 + //wall is wall
162 + //
163 + fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dkbytes\n",
164 + wall_time, user_time, system_time, mem_usage);
165 + }
166 +
167 + static void
168 + final_stats(struct rusage *rus)
169 + {
170 + struct timeval total, now, wall;
171 + timeradd(&rus->ru_utime, &rus->ru_stime, &total);
172 + total_ms = total.tv_sec*1000 + total.tv_usec/1000;
173 + gettimeofday(&now, NULL);
174 + timersub(&now, &start_time, &wall);
175 + wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000;
176 + sys_ms = rus->ru_stime.tv_sec * 1000 + rus->ru_stime.tv_usec / 1000;
177 +
178 + meta_printf("time:%d.%03d\n", total_ms/1000, total_ms%1000);
179 + meta_printf("time-wall:%d.%03d\n", wall_ms/1000, wall_ms%1000);
180 + meta_printf("mem:%llu\n", (unsigned long long) mem_peak_kb * 1024);
181 + }
182 +
183 + /*** Messages and exits ***/
184 +
185 + static void NONRET
186 + box_exit(int rc)
187 + {
188 + if (box_pid > 0)
189 + {
190 + sample_mem_peak();
191 + if (is_ptraced)
192 + ptrace(PTRACE_KILL, box_pid);
193 + kill(-box_pid, SIGKILL);
194 + kill(box_pid, SIGKILL);
195 + meta_printf("killed:1\n");
196 +
197 + struct rusage rus;
198 + int p, stat;
199 + do
200 + p = wait4(box_pid, &stat, 0, &rus);
201 + while (p < 0 && errno == EINTR);
202 + if (p < 0)
203 + fprintf(stderr, "UGH: Lost track of the process (%m)\n");
204 + else {
205 + final_stats(&rus);
206 + }
207 + }
208 + print_running_stat(
209 + (double)wall_ms/1000,
210 + (double)total_ms/1000,
211 + (double)sys_ms/1000,
212 + mem_peak_kb);
213 + meta_close();
214 + exit(rc);
215 + }
216 +
217 + static void
218 + flush_line(void)
219 + {
220 + if (partial_line)
221 + fputc('\n', stderr);
222 + partial_line = 0;
223 + }
224 +
225 + /* Report an error of the sandbox itself */
226 + static void NONRET __attribute__((format(printf,1,2)))
227 + die(char *msg, ...)
228 + {
229 + va_list args;
230 + va_start(args, msg);
231 + flush_line();
232 + char buf[1024];
233 + vsnprintf(buf, sizeof(buf), msg, args);
234 + meta_printf("status:XX\nmessage:%s\n", buf);
235 + fputs(buf, stderr);
236 + fputc('\n', stderr);
237 + box_exit(2);
238 + }
239 +
240 + /* Report an error of the program inside the sandbox */
241 + static void NONRET __attribute__((format(printf,1,2)))
242 + err(char *msg, ...)
243 + {
244 + va_list args;
245 + va_start(args, msg);
246 + flush_line();
247 + if (msg[0] && msg[1] && msg[2] == ':' && msg[3] == ' ')
248 + {
249 + meta_printf("status:%c%c\n", msg[0], msg[1]);
250 + msg += 4;
251 + }
252 + char buf[1024];
253 + vsnprintf(buf, sizeof(buf), msg, args);
254 + meta_printf("message:%s\n", buf);
255 + fputs(buf, stderr);
256 + fputc('\n', stderr);
257 + box_exit(1);
258 + }
259 +
260 + /* Write a message, but only if in verbose mode */
261 + static void __attribute__((format(printf,1,2)))
262 + msg(char *msg, ...)
263 + {
264 + va_list args;
265 + va_start(args, msg);
266 + if (verbose)
267 + {
268 + int len = strlen(msg);
269 + if (len > 0)
270 + partial_line = (msg[len-1] != '\n');
271 + vfprintf(stderr, msg, args);
272 + fflush(stderr);
273 + }
274 + va_end(args);
275 + }
276 +
277 + static void *
278 + xmalloc(size_t size)
279 + {
280 + void *p = malloc(size);
281 + if (!p)
282 + die("Out of memory");
283 + return p;
284 + }
285 +
286 + /*** Syscall rules ***/
287 +
288 + static const char * const syscall_names[] = {
289 +
290 + /* Syscall table automatically generated by mk-syscall-table */
291 +
292 + /* 0 */ [ __NR_read ] = "read",
293 + /* 1 */ [ __NR_write ] = "write",
294 + /* 2 */ [ __NR_open ] = "open",
295 + /* 3 */ [ __NR_close ] = "close",
296 + /* 4 */ [ __NR_stat ] = "stat",
297 + /* 5 */ [ __NR_fstat ] = "fstat",
298 + /* 6 */ [ __NR_lstat ] = "lstat",
299 + /* 7 */ [ __NR_poll ] = "poll",
300 + /* 8 */ [ __NR_lseek ] = "lseek",
301 + /* 9 */ [ __NR_mmap ] = "mmap",
302 + /* 10 */ [ __NR_mprotect ] = "mprotect",
303 + /* 11 */ [ __NR_munmap ] = "munmap",
304 + /* 12 */ [ __NR_brk ] = "brk",
305 + /* 13 */ [ __NR_rt_sigaction ] = "rt_sigaction",
306 + /* 14 */ [ __NR_rt_sigprocmask ] = "rt_sigprocmask",
307 + /* 15 */ [ __NR_rt_sigreturn ] = "rt_sigreturn",
308 + /* 16 */ [ __NR_ioctl ] = "ioctl",
309 + /* 17 */ [ __NR_pread64 ] = "pread64",
310 + /* 18 */ [ __NR_pwrite64 ] = "pwrite64",
311 + /* 19 */ [ __NR_readv ] = "readv",
312 + /* 20 */ [ __NR_writev ] = "writev",
313 + /* 21 */ [ __NR_access ] = "access",
314 + /* 22 */ [ __NR_pipe ] = "pipe",
315 + /* 23 */ [ __NR_select ] = "select",
316 + /* 24 */ [ __NR_sched_yield ] = "sched_yield",
317 + /* 25 */ [ __NR_mremap ] = "mremap",
318 + /* 26 */ [ __NR_msync ] = "msync",
319 + /* 27 */ [ __NR_mincore ] = "mincore",
320 + /* 28 */ [ __NR_madvise ] = "madvise",
321 + /* 29 */ [ __NR_shmget ] = "shmget",
322 + /* 30 */ [ __NR_shmat ] = "shmat",
323 + /* 31 */ [ __NR_shmctl ] = "shmctl",
324 + /* 32 */ [ __NR_dup ] = "dup",
325 + /* 33 */ [ __NR_dup2 ] = "dup2",
326 + /* 34 */ [ __NR_pause ] = "pause",
327 + /* 35 */ [ __NR_nanosleep ] = "nanosleep",
328 + /* 36 */ [ __NR_getitimer ] = "getitimer",
329 + /* 37 */ [ __NR_alarm ] = "alarm",
330 + /* 38 */ [ __NR_setitimer ] = "setitimer",
331 + /* 39 */ [ __NR_getpid ] = "getpid",
332 + /* 40 */ [ __NR_sendfile ] = "sendfile",
333 + /* 41 */ [ __NR_socket ] = "socket",
334 + /* 42 */ [ __NR_connect ] = "connect",
335 + /* 43 */ [ __NR_accept ] = "accept",
336 + /* 44 */ [ __NR_sendto ] = "sendto",
337 + /* 45 */ [ __NR_recvfrom ] = "recvfrom",
338 + /* 46 */ [ __NR_sendmsg ] = "sendmsg",
339 + /* 47 */ [ __NR_recvmsg ] = "recvmsg",
340 + /* 48 */ [ __NR_shutdown ] = "shutdown",
341 + /* 49 */ [ __NR_bind ] = "bind",
342 + /* 50 */ [ __NR_listen ] = "listen",
343 + /* 51 */ [ __NR_getsockname ] = "getsockname",
344 + /* 52 */ [ __NR_getpeername ] = "getpeername",
345 + /* 53 */ [ __NR_socketpair ] = "socketpair",
346 + /* 54 */ [ __NR_setsockopt ] = "setsockopt",
347 + /* 55 */ [ __NR_getsockopt ] = "getsockopt",
348 + /* 56 */ [ __NR_clone ] = "clone",
349 + /* 57 */ [ __NR_fork ] = "fork",
350 + /* 58 */ [ __NR_vfork ] = "vfork",
351 + /* 59 */ [ __NR_execve ] = "execve",
352 + /* 60 */ [ __NR_exit ] = "exit",
353 + /* 61 */ [ __NR_wait4 ] = "wait4",
354 + /* 62 */ [ __NR_kill ] = "kill",
355 + /* 63 */ [ __NR_uname ] = "uname",
356 + /* 64 */ [ __NR_semget ] = "semget",
357 + /* 65 */ [ __NR_semop ] = "semop",
358 + /* 66 */ [ __NR_semctl ] = "semctl",
359 + /* 67 */ [ __NR_shmdt ] = "shmdt",
360 + /* 68 */ [ __NR_msgget ] = "msgget",
361 + /* 69 */ [ __NR_msgsnd ] = "msgsnd",
362 + /* 70 */ [ __NR_msgrcv ] = "msgrcv",
363 + /* 71 */ [ __NR_msgctl ] = "msgctl",
364 + /* 72 */ [ __NR_fcntl ] = "fcntl",
365 + /* 73 */ [ __NR_flock ] = "flock",
366 + /* 74 */ [ __NR_fsync ] = "fsync",
367 + /* 75 */ [ __NR_fdatasync ] = "fdatasync",
368 + /* 76 */ [ __NR_truncate ] = "truncate",
369 + /* 77 */ [ __NR_ftruncate ] = "ftruncate",
370 + /* 78 */ [ __NR_getdents ] = "getdents",
371 + /* 79 */ [ __NR_getcwd ] = "getcwd",
372 + /* 80 */ [ __NR_chdir ] = "chdir",
373 + /* 81 */ [ __NR_fchdir ] = "fchdir",
374 + /* 82 */ [ __NR_rename ] = "rename",
375 + /* 83 */ [ __NR_mkdir ] = "mkdir",
376 + /* 84 */ [ __NR_rmdir ] = "rmdir",
377 + /* 85 */ [ __NR_creat ] = "creat",
378 + /* 86 */ [ __NR_link ] = "link",
379 + /* 87 */ [ __NR_unlink ] = "unlink",
380 + /* 88 */ [ __NR_symlink ] = "symlink",
381 + /* 89 */ [ __NR_readlink ] = "readlink",
382 + /* 90 */ [ __NR_chmod ] = "chmod",
383 + /* 91 */ [ __NR_fchmod ] = "fchmod",
384 + /* 92 */ [ __NR_chown ] = "chown",
385 + /* 93 */ [ __NR_fchown ] = "fchown",
386 + /* 94 */ [ __NR_lchown ] = "lchown",
387 + /* 95 */ [ __NR_umask ] = "umask",
388 + /* 96 */ [ __NR_gettimeofday ] = "gettimeofday",
389 + /* 97 */ [ __NR_getrlimit ] = "getrlimit",
390 + /* 98 */ [ __NR_getrusage ] = "getrusage",
391 + /* 99 */ [ __NR_sysinfo ] = "sysinfo",
392 + /* 100 */ [ __NR_times ] = "times",
393 + /* 101 */ [ __NR_ptrace ] = "ptrace",
394 + /* 102 */ [ __NR_getuid ] = "getuid",
395 + /* 103 */ [ __NR_syslog ] = "syslog",
396 + /* 104 */ [ __NR_getgid ] = "getgid",
397 + /* 105 */ [ __NR_setuid ] = "setuid",
398 + /* 106 */ [ __NR_setgid ] = "setgid",
399 + /* 107 */ [ __NR_geteuid ] = "geteuid",
400 + /* 108 */ [ __NR_getegid ] = "getegid",
401 + /* 109 */ [ __NR_setpgid ] = "setpgid",
402 + /* 110 */ [ __NR_getppid ] = "getppid",
403 + /* 111 */ [ __NR_getpgrp ] = "getpgrp",
404 + /* 112 */ [ __NR_setsid ] = "setsid",
405 + /* 113 */ [ __NR_setreuid ] = "setreuid",
406 + /* 114 */ [ __NR_setregid ] = "setregid",
407 + /* 115 */ [ __NR_getgroups ] = "getgroups",
408 + /* 116 */ [ __NR_setgroups ] = "setgroups",
409 + /* 117 */ [ __NR_setresuid ] = "setresuid",
410 + /* 118 */ [ __NR_getresuid ] = "getresuid",
411 + /* 119 */ [ __NR_setresgid ] = "setresgid",
412 + /* 120 */ [ __NR_getresgid ] = "getresgid",
413 + /* 121 */ [ __NR_getpgid ] = "getpgid",
414 + /* 122 */ [ __NR_setfsuid ] = "setfsuid",
415 + /* 123 */ [ __NR_setfsgid ] = "setfsgid",
416 + /* 124 */ [ __NR_getsid ] = "getsid",
417 + /* 125 */ [ __NR_capget ] = "capget",
418 + /* 126 */ [ __NR_capset ] = "capset",
419 + /* 127 */ [ __NR_rt_sigpending ] = "rt_sigpending",
420 + /* 128 */ [ __NR_rt_sigtimedwait ] = "rt_sigtimedwait",
421 + /* 129 */ [ __NR_rt_sigqueueinfo ] = "rt_sigqueueinfo",
422 + /* 130 */ [ __NR_rt_sigsuspend ] = "rt_sigsuspend",
423 + /* 131 */ [ __NR_sigaltstack ] = "sigaltstack",
424 + /* 132 */ [ __NR_utime ] = "utime",
425 + /* 133 */ [ __NR_mknod ] = "mknod",
426 + /* 134 */ [ __NR_uselib ] = "uselib",
427 + /* 135 */ [ __NR_personality ] = "personality",
428 + /* 136 */ [ __NR_ustat ] = "ustat",
429 + /* 137 */ [ __NR_statfs ] = "statfs",
430 + /* 138 */ [ __NR_fstatfs ] = "fstatfs",
431 + /* 139 */ [ __NR_sysfs ] = "sysfs",
432 + /* 140 */ [ __NR_getpriority ] = "getpriority",
433 + /* 141 */ [ __NR_setpriority ] = "setpriority",
434 + /* 142 */ [ __NR_sched_setparam ] = "sched_setparam",
435 + /* 143 */ [ __NR_sched_getparam ] = "sched_getparam",
436 + /* 144 */ [ __NR_sched_setscheduler ] = "sched_setscheduler",
437 + /* 145 */ [ __NR_sched_getscheduler ] = "sched_getscheduler",
438 + /* 146 */ [ __NR_sched_get_priority_max ] = "sched_get_priority_max",
439 + /* 147 */ [ __NR_sched_get_priority_min ] = "sched_get_priority_min",
440 + /* 148 */ [ __NR_sched_rr_get_interval ] = "sched_rr_get_interval",
441 + /* 149 */ [ __NR_mlock ] = "mlock",
442 + /* 150 */ [ __NR_munlock ] = "munlock",
443 + /* 151 */ [ __NR_mlockall ] = "mlockall",
444 + /* 152 */ [ __NR_munlockall ] = "munlockall",
445 + /* 153 */ [ __NR_vhangup ] = "vhangup",
446 + /* 154 */ [ __NR_modify_ldt ] = "modify_ldt",
447 + /* 155 */ [ __NR_pivot_root ] = "pivot_root",
448 + /* 156 */ [ __NR__sysctl ] = "_sysctl",
449 + /* 157 */ [ __NR_prctl ] = "prctl",
450 + /* 158 */ [ __NR_arch_prctl ] = "arch_prctl",
451 + /* 159 */ [ __NR_adjtimex ] = "adjtimex",
452 + /* 160 */ [ __NR_setrlimit ] = "setrlimit",
453 + /* 161 */ [ __NR_chroot ] = "chroot",
454 + /* 162 */ [ __NR_sync ] = "sync",
455 + /* 163 */ [ __NR_acct ] = "acct",
456 + /* 164 */ [ __NR_settimeofday ] = "settimeofday",
457 + /* 165 */ [ __NR_mount ] = "mount",
458 + /* 166 */ [ __NR_umount2 ] = "umount2",
459 + /* 167 */ [ __NR_swapon ] = "swapon",
460 + /* 168 */ [ __NR_swapoff ] = "swapoff",
461 + /* 169 */ [ __NR_reboot ] = "reboot",
462 + /* 170 */ [ __NR_sethostname ] = "sethostname",
463 + /* 171 */ [ __NR_setdomainname ] = "setdomainname",
464 + /* 172 */ [ __NR_iopl ] = "iopl",
465 + /* 173 */ [ __NR_ioperm ] = "ioperm",
466 + /* 174 */ [ __NR_create_module ] = "create_module",
467 + /* 175 */ [ __NR_init_module ] = "init_module",
468 + /* 176 */ [ __NR_delete_module ] = "delete_module",
469 + /* 177 */ [ __NR_get_kernel_syms ] = "get_kernel_syms",
470 + /* 178 */ [ __NR_query_module ] = "query_module",
471 + /* 179 */ [ __NR_quotactl ] = "quotactl",
472 + /* 180 */ [ __NR_nfsservctl ] = "nfsservctl",
473 + /* 181 */ [ __NR_getpmsg ] = "getpmsg",
474 + /* 182 */ [ __NR_putpmsg ] = "putpmsg",
475 + /* 183 */ [ __NR_afs_syscall ] = "afs_syscall",
476 + /* 184 */ [ __NR_tuxcall ] = "tuxcall",
477 + /* 185 */ [ __NR_security ] = "security",
478 + /* 186 */ [ __NR_gettid ] = "gettid",
479 + /* 187 */ [ __NR_readahead ] = "readahead",
480 + /* 188 */ [ __NR_setxattr ] = "setxattr",
481 + /* 189 */ [ __NR_lsetxattr ] = "lsetxattr",
482 + /* 190 */ [ __NR_fsetxattr ] = "fsetxattr",
483 + /* 191 */ [ __NR_getxattr ] = "getxattr",
484 + /* 192 */ [ __NR_lgetxattr ] = "lgetxattr",
485 + /* 193 */ [ __NR_fgetxattr ] = "fgetxattr",
486 + /* 194 */ [ __NR_listxattr ] = "listxattr",
487 + /* 195 */ [ __NR_llistxattr ] = "llistxattr",
488 + /* 196 */ [ __NR_flistxattr ] = "flistxattr",
489 + /* 197 */ [ __NR_removexattr ] = "removexattr",
490 + /* 198 */ [ __NR_lremovexattr ] = "lremovexattr",
491 + /* 199 */ [ __NR_fremovexattr ] = "fremovexattr",
492 + /* 200 */ [ __NR_tkill ] = "tkill",
493 + /* 201 */ [ __NR_time ] = "time",
494 + /* 202 */ [ __NR_futex ] = "futex",
495 + /* 203 */ [ __NR_sched_setaffinity ] = "sched_setaffinity",
496 + /* 204 */ [ __NR_sched_getaffinity ] = "sched_getaffinity",
497 + /* 205 */ [ __NR_set_thread_area ] = "set_thread_area",
498 + /* 206 */ [ __NR_io_setup ] = "io_setup",
499 + /* 207 */ [ __NR_io_destroy ] = "io_destroy",
500 + /* 208 */ [ __NR_io_getevents ] = "io_getevents",
501 + /* 209 */ [ __NR_io_submit ] = "io_submit",
502 + /* 210 */ [ __NR_io_cancel ] = "io_cancel",
503 + /* 211 */ [ __NR_get_thread_area ] = "get_thread_area",
504 + /* 212 */ [ __NR_lookup_dcookie ] = "lookup_dcookie",
505 + /* 213 */ [ __NR_epoll_create ] = "epoll_create",
506 + /* 214 */ [ __NR_epoll_ctl_old ] = "epoll_ctl_old",
507 + /* 215 */ [ __NR_epoll_wait_old ] = "epoll_wait_old",
508 + /* 216 */ [ __NR_remap_file_pages ] = "remap_file_pages",
509 + /* 217 */ [ __NR_getdents64 ] = "getdents64",
510 + /* 218 */ [ __NR_set_tid_address ] = "set_tid_address",
511 + /* 219 */ [ __NR_restart_syscall ] = "restart_syscall",
512 + /* 220 */ [ __NR_semtimedop ] = "semtimedop",
513 + /* 221 */ [ __NR_fadvise64 ] = "fadvise64",
514 + /* 222 */ [ __NR_timer_create ] = "timer_create",
515 + /* 223 */ [ __NR_timer_settime ] = "timer_settime",
516 + /* 224 */ [ __NR_timer_gettime ] = "timer_gettime",
517 + /* 225 */ [ __NR_timer_getoverrun ] = "timer_getoverrun",
518 + /* 226 */ [ __NR_timer_delete ] = "timer_delete",
519 + /* 227 */ [ __NR_clock_settime ] = "clock_settime",
520 + /* 228 */ [ __NR_clock_gettime ] = "clock_gettime",
521 + /* 229 */ [ __NR_clock_getres ] = "clock_getres",
522 + /* 230 */ [ __NR_clock_nanosleep ] = "clock_nanosleep",
523 + /* 231 */ [ __NR_exit_group ] = "exit_group",
524 + /* 232 */ [ __NR_epoll_wait ] = "epoll_wait",
525 + /* 233 */ [ __NR_epoll_ctl ] = "epoll_ctl",
526 + /* 234 */ [ __NR_tgkill ] = "tgkill",
527 + /* 235 */ [ __NR_utimes ] = "utimes",
528 + /* 236 */ [ __NR_vserver ] = "vserver",
529 + /* 237 */ [ __NR_mbind ] = "mbind",
530 + /* 238 */ [ __NR_set_mempolicy ] = "set_mempolicy",
531 + /* 239 */ [ __NR_get_mempolicy ] = "get_mempolicy",
532 + /* 240 */ [ __NR_mq_open ] = "mq_open",
533 + /* 241 */ [ __NR_mq_unlink ] = "mq_unlink",
534 + /* 242 */ [ __NR_mq_timedsend ] = "mq_timedsend",
535 + /* 243 */ [ __NR_mq_timedreceive ] = "mq_timedreceive",
536 + /* 244 */ [ __NR_mq_notify ] = "mq_notify",
537 + /* 245 */ [ __NR_mq_getsetattr ] = "mq_getsetattr",
538 + /* 246 */ [ __NR_kexec_load ] = "kexec_load",
539 + /* 247 */ [ __NR_waitid ] = "waitid",
540 + /* 248 */ [ __NR_add_key ] = "add_key",
541 + /* 249 */ [ __NR_request_key ] = "request_key",
542 + /* 250 */ [ __NR_keyctl ] = "keyctl",
543 + /* 251 */ [ __NR_ioprio_set ] = "ioprio_set",
544 + /* 252 */ [ __NR_ioprio_get ] = "ioprio_get",
545 + /* 253 */ [ __NR_inotify_init ] = "inotify_init",
546 + /* 254 */ [ __NR_inotify_add_watch ] = "inotify_add_watch",
547 + /* 255 */ [ __NR_inotify_rm_watch ] = "inotify_rm_watch",
548 + /* 256 */ [ __NR_migrate_pages ] = "migrate_pages",
549 + /* 257 */ [ __NR_openat ] = "openat",
550 + /* 258 */ [ __NR_mkdirat ] = "mkdirat",
551 + /* 259 */ [ __NR_mknodat ] = "mknodat",
552 + /* 260 */ [ __NR_fchownat ] = "fchownat",
553 + /* 261 */ [ __NR_futimesat ] = "futimesat",
554 + /* 262 */ [ __NR_newfstatat ] = "newfstatat",
555 + /* 263 */ [ __NR_unlinkat ] = "unlinkat",
556 + /* 264 */ [ __NR_renameat ] = "renameat",
557 + /* 265 */ [ __NR_linkat ] = "linkat",
558 + /* 266 */ [ __NR_symlinkat ] = "symlinkat",
559 + /* 267 */ [ __NR_readlinkat ] = "readlinkat",
560 + /* 268 */ [ __NR_fchmodat ] = "fchmodat",
561 + /* 269 */ [ __NR_faccessat ] = "faccessat",
562 + /* 270 */ [ __NR_pselect6 ] = "pselect6",
563 + /* 271 */ [ __NR_ppoll ] = "ppoll",
564 + /* 272 */ [ __NR_unshare ] = "unshare",
565 + /* 273 */ [ __NR_set_robust_list ] = "set_robust_list",
566 + /* 274 */ [ __NR_get_robust_list ] = "get_robust_list",
567 + /* 275 */ [ __NR_splice ] = "splice",
568 + /* 276 */ [ __NR_tee ] = "tee",
569 + /* 277 */ [ __NR_sync_file_range ] = "sync_file_range",
570 + /* 278 */ [ __NR_vmsplice ] = "vmsplice",
571 + /* 279 */ [ __NR_move_pages ] = "move_pages",
572 + /* 280 */ [ __NR_utimensat ] = "utimensat",
573 + /* 281 */ [ __NR_epoll_pwait ] = "epoll_pwait",
574 + /* 282 */ [ __NR_signalfd ] = "signalfd",
575 + /* 283 */ [ __NR_timerfd_create ] = "timerfd_create",
576 + /* 284 */ [ __NR_eventfd ] = "eventfd",
577 + /* 285 */ [ __NR_fallocate ] = "fallocate",
578 + /* 286 */ [ __NR_timerfd_settime ] = "timerfd_settime",
579 + /* 287 */ [ __NR_timerfd_gettime ] = "timerfd_gettime",
580 + /* 288 */ [ __NR_accept4 ] = "accept4",
581 + /* 289 */ [ __NR_signalfd4 ] = "signalfd4",
582 + /* 290 */ [ __NR_eventfd2 ] = "eventfd2",
583 + /* 291 */ [ __NR_epoll_create1 ] = "epoll_create1",
584 + /* 292 */ [ __NR_dup3 ] = "dup3",
585 + /* 293 */ [ __NR_pipe2 ] = "pipe2",
586 + /* 294 */ [ __NR_inotify_init1 ] = "inotify_init1",
587 + /* 295 */ [ __NR_preadv ] = "preadv",
588 + /* 296 */ [ __NR_pwritev ] = "pwritev",
589 + /* 297 */ [ __NR_rt_tgsigqueueinfo ] = "rt_tgsigqueueinfo",
590 + /* 298 */ [ __NR_perf_event_open ] = "perf_event_open",
591 + /* 299 */ [ __NR_recvmmsg ] = "recvmmsg",
592 + /* 300 */ [ __NR_fanotify_init ] = "fanotify_init",
593 + /* 301 */ [ __NR_fanotify_mark ] = "fanotify_mark",
594 + /* 302 */ [ __NR_prlimit64 ] = "prlimit64",
595 + /* 303 */ [ __NR_name_to_handle_at ] = "name_to_handle_at",
596 + /* 304 */ [ __NR_open_by_handle_at ] = "open_by_handle_at",
597 + /* 305 */ [ __NR_clock_adjtime ] = "clock_adjtime",
598 + /* 306 */ [ __NR_syncfs ] = "syncfs",
599 + /* 307 */ [ __NR_sendmmsg ] = "sendmmsg",
600 + /* 308 */ [ __NR_setns ] = "setns",
601 + /* 309 */ [ __NR_getcpu ] = "getcpu",
602 + /* 310 */ [ __NR_process_vm_readv ] = "process_vm_readv",
603 + /* 311 */ [ __NR_process_vm_writev ] = "process_vm_writev",
604 + /* 312 */ [ __NR_kcmp ] = "kcmp",
605 + /* 313 */ [ __NR_finit_module ] = "finit_module",
606 + };
607 + #define NUM_SYSCALLS ARRAY_SIZE(syscall_names)
608 + #define NUM_ACTIONS (NUM_SYSCALLS+64)
609 +
610 + enum action {
611 + A_DEFAULT, // Use the default action
612 + A_NO, // Always forbid
613 + A_YES, // Always permit
614 + A_FILENAME, // Permit if arg1 is a known filename
615 + A_ACTION_MASK = 15,
616 + A_NO_RETVAL = 32, // Does not return a value
617 + A_SAMPLE_MEM = 64, // Sample memory usage before the syscall
618 + A_LIBERAL = 128, // Valid only in liberal mode
619 + // Must fit in a unsigned char
620 + };
621 +
622 + static unsigned char syscall_action[NUM_ACTIONS] = {
623 + #define S(x) [__NR_##x]
624 +
625 + // Syscalls permitted for specific file names
626 + S(open) = A_FILENAME,
627 + S(creat) = A_FILENAME,
628 + S(unlink) = A_FILENAME,
629 + S(access) = A_FILENAME,
630 + S(truncate) = A_FILENAME,
631 + S(stat) = A_FILENAME,
632 + S(lstat) = A_FILENAME,
633 + S(readlink) = A_FILENAME,
634 + #ifndef CONFIG_BOX_USER_AMD64
635 + S(oldstat) = A_FILENAME,
636 + S(oldlstat) = A_FILENAME,
637 + S(truncate64) = A_FILENAME,
638 + S(stat64) = A_FILENAME,
639 + S(lstat64) = A_FILENAME,
640 + #endif
641 +
642 + // Syscalls permitted always
643 + S(exit) = A_YES | A_SAMPLE_MEM,
644 + S(read) = A_YES,
645 + S(write) = A_YES,
646 + S(close) = A_YES,
647 + S(lseek) = A_YES,
648 + S(getpid) = A_YES,
649 + S(getuid) = A_YES,
650 + S(dup) = A_YES,
651 + S(brk) = A_YES,
652 + S(getgid) = A_YES,
653 + S(geteuid) = A_YES,
654 + S(getegid) = A_YES,
655 + S(dup2) = A_YES,
656 + S(ftruncate) = A_YES,
657 + S(fstat) = A_YES,
658 + S(personality) = A_YES,
659 + S(readv) = A_YES,
660 + S(writev) = A_YES,
661 + S(getresuid) = A_YES,
662 + #ifdef __NR_pread64
663 + S(pread64) = A_YES,
664 + S(pwrite64) = A_YES,
665 + #else
666 + S(pread) = A_YES,
667 + S(pwrite) = A_YES,
668 + #endif
669 + S(fcntl) = A_YES,
670 + S(mmap) = A_YES,
671 + S(munmap) = A_YES,
672 + S(ioctl) = A_YES,
673 + S(uname) = A_YES,
674 + S(gettid) = A_YES,
675 + S(set_thread_area) = A_YES,
676 + S(get_thread_area) = A_YES,
677 + S(set_tid_address) = A_YES,
678 + S(exit_group) = A_YES | A_SAMPLE_MEM,
679 + #ifdef CONFIG_BOX_USER_AMD64
680 + S(arch_prctl) = A_YES,
681 + #else
682 + S(oldfstat) = A_YES,
683 + S(ftruncate64) = A_YES,
684 + S(_llseek) = A_YES,
685 + S(fstat64) = A_YES,
686 + S(fcntl64) = A_YES,
687 + S(mmap2) = A_YES,
688 + #endif
689 +
690 + // Syscalls permitted only in liberal mode
691 + S(time) = A_YES | A_LIBERAL,
692 + S(alarm) = A_YES | A_LIBERAL,
693 + S(pause) = A_YES | A_LIBERAL,
694 + S(fchmod) = A_YES | A_LIBERAL,
695 + S(getrlimit) = A_YES | A_LIBERAL,
696 + S(getrusage) = A_YES | A_LIBERAL,
697 + S(gettimeofday) = A_YES | A_LIBERAL,
698 + S(select) = A_YES | A_LIBERAL,
699 + S(setitimer) = A_YES | A_LIBERAL,
700 + S(getitimer) = A_YES | A_LIBERAL,
701 + S(mprotect) = A_YES | A_LIBERAL,
702 + S(getdents) = A_YES | A_LIBERAL,
703 + S(getdents64) = A_YES | A_LIBERAL,
704 + S(fdatasync) = A_YES | A_LIBERAL,
705 + S(mremap) = A_YES | A_LIBERAL,
706 + S(poll) = A_YES | A_LIBERAL,
707 + S(getcwd) = A_YES | A_LIBERAL,
708 + S(nanosleep) = A_YES | A_LIBERAL,
709 + S(rt_sigreturn) = A_YES | A_LIBERAL | A_NO_RETVAL,
710 + S(rt_sigaction) = A_YES | A_LIBERAL,
711 + S(rt_sigprocmask) = A_YES | A_LIBERAL,
712 + S(rt_sigpending) = A_YES | A_LIBERAL,
713 + S(rt_sigtimedwait) = A_YES | A_LIBERAL,
714 + S(rt_sigqueueinfo) = A_YES | A_LIBERAL,
715 + S(rt_sigsuspend) = A_YES | A_LIBERAL,
716 + S(_sysctl) = A_YES | A_LIBERAL,
717 + #ifndef CONFIG_BOX_USER_AMD64
718 + S(sigaction) = A_YES | A_LIBERAL,
719 + S(sgetmask) = A_YES | A_LIBERAL,
720 + S(ssetmask) = A_YES | A_LIBERAL,
721 + S(sigsuspend) = A_YES | A_LIBERAL,
722 + S(sigpending) = A_YES | A_LIBERAL,
723 + S(sigreturn) = A_YES | A_LIBERAL | A_NO_RETVAL,
724 + S(sigprocmask) = A_YES | A_LIBERAL,
725 + S(ugetrlimit) = A_YES | A_LIBERAL,
726 + S(readdir) = A_YES | A_LIBERAL,
727 + S(signal) = A_YES | A_LIBERAL,
728 + S(_newselect) = A_YES | A_LIBERAL,
729 + #endif
730 +
731 + #undef S
732 + };
733 +
734 + static const char *
735 + syscall_name(unsigned int id, char *buf)
736 + {
737 + if (id < NUM_SYSCALLS && syscall_names[id])
738 + return syscall_names[id];
739 + else
740 + {
741 + sprintf(buf, "#%d", id);
742 + return buf;
743 + }
744 + }
745 +
746 + static int
747 + syscall_by_name(char *name)
748 + {
749 + for (unsigned int i=0; i<NUM_SYSCALLS; i++)
750 + if (syscall_names[i] && !strcmp(syscall_names[i], name))
751 + return i;
752 + if (name[0] == '#')
753 + name++;
754 + if (!*name)
755 + return -1;
756 + char *ep;
757 + unsigned long l = strtoul(name, &ep, 0);
758 + if (*ep)
759 + return -1;
760 + if (l >= NUM_ACTIONS)
761 + return NUM_ACTIONS;
762 + return l;
763 + }
764 +
765 + static int
766 + set_syscall_action(char *a)
767 + {
768 + char *sep = strchr(a, '=');
769 + enum action act = A_YES;
770 + if (sep)
771 + {
772 + *sep++ = 0;
773 + if (!strcmp(sep, "yes"))
774 + act = A_YES;
775 + else if (!strcmp(sep, "no"))
776 + act = A_NO;
777 + else if (!strcmp(sep, "file"))
778 + act = A_FILENAME;
779 + else
780 + return 0;
781 + }
782 +
783 + int sys = syscall_by_name(a);
784 + if (sys < 0)
785 + die("Unknown syscall `%s'", a);
786 + if (sys >= NUM_ACTIONS)
787 + die("Syscall `%s' out of range", a);
788 + syscall_action[sys] = act;
789 + return 1;
790 + }
791 +
792 + /*** Path rules ***/
793 +
794 + struct path_rule {
795 + char *path;
796 + enum action action;
797 + struct path_rule *next;
798 + };
799 +
800 + static struct path_rule default_path_rules[] = {
801 + { "/etc/", A_YES },
802 + { "/lib/", A_YES },
803 + { "/usr/lib/", A_YES },
804 + { "/opt/lib/", A_YES },
805 + { "/usr/share/zoneinfo/", A_YES },
806 + { "/usr/share/locale/", A_YES },
807 + { "/dev/null", A_YES },
808 + { "/dev/zero", A_YES },
809 + { "/proc/meminfo", A_YES },
810 + { "/proc/self/stat", A_YES },
811 + { "/proc/self/exe", A_YES }, // Needed by FPC 2.0.x runtime
812 + { "/proc/self/maps", A_YES }, // Needed by glibc when it reports arena corruption
813 + };
814 +
815 + static struct path_rule *user_path_rules;
816 + static struct path_rule **last_path_rule = &user_path_rules;
817 +
818 + static int
819 + set_path_action(char *a)
820 + {
821 + char *sep = strchr(a, '=');
822 + enum action act = A_YES;
823 + if (sep)
824 + {
825 + *sep++ = 0;
826 + if (!strcmp(sep, "yes"))
827 + act = A_YES;
828 + else if (!strcmp(sep, "no"))
829 + act = A_NO;
830 + else
831 + return 0;
832 + }
833 +
834 + struct path_rule *r = xmalloc(sizeof(*r) + strlen(a) + 1);
835 + r->path = (char *)(r+1);
836 + strcpy(r->path, a);
837 + r->action = act;
838 + r->next = NULL;
839 + *last_path_rule = r;
840 + last_path_rule = &r->next;
841 + return 1;
842 + }
843 +
844 + static enum action
845 + match_path_rule(struct path_rule *r, char *path)
846 + {
847 + char *rr = r->path;
848 + while (*rr)
849 + if (*rr++ != *path++)
850 + {
851 + if (rr[-1] == '/' && !path[-1])
852 + break;
853 + return A_DEFAULT;
854 + }
855 + if (rr > r->path && rr[-1] != '/' && *path)
856 + return A_DEFAULT;
857 + return r->action;
858 + }
859 +
860 + /*** Environment rules ***/
861 +
862 + struct env_rule {
863 + char *var; // Variable to match
864 + char *val; // ""=clear, NULL=inherit
865 + int var_len;
866 + struct env_rule *next;
867 + };
868 +
869 + static struct env_rule *first_env_rule;
870 + static struct env_rule **last_env_rule = &first_env_rule;
871 +
872 + static struct env_rule default_env_rules[] = {
873 + { "LIBC_FATAL_STDERR_", "1" }
874 + };
875 +
876 + static int
877 + set_env_action(char *a0)
878 + {
879 + struct env_rule *r = xmalloc(sizeof(*r) + strlen(a0) + 1);
880 + char *a = (char *)(r+1);
881 + strcpy(a, a0);
882 +
883 + char *sep = strchr(a, '=');
884 + if (sep == a)
885 + return 0;
886 + r->var = a;
887 + if (sep)
888 + {
889 + *sep++ = 0;
890 + r->val = sep;
891 + }
892 + else
893 + r->val = NULL;
894 + *last_env_rule = r;
895 + last_env_rule = &r->next;
896 + r->next = NULL;
897 + return 1;
898 + }
899 +
900 + static int
901 + match_env_var(char *env_entry, struct env_rule *r)
902 + {
903 + if (strncmp(env_entry, r->var, r->var_len))
904 + return 0;
905 + return (env_entry[r->var_len] == '=');
906 + }
907 +
908 + static void
909 + apply_env_rule(char **env, int *env_sizep, struct env_rule *r)
910 + {
911 + // First remove the variable if already set
912 + int pos = 0;
913 + while (pos < *env_sizep && !match_env_var(env[pos], r))
914 + pos++;
915 + if (pos < *env_sizep)
916 + {
917 + (*env_sizep)--;
918 + env[pos] = env[*env_sizep];
919 + env[*env_sizep] = NULL;
920 + }
921 +
922 + // What is the new value?
923 + char *new;
924 + if (r->val)
925 + {
926 + if (!r->val[0])
927 + return;
928 + new = xmalloc(r->var_len + 1 + strlen(r->val) + 1);
929 + sprintf(new, "%s=%s", r->var, r->val);
930 + }
931 + else
932 + {
933 + pos = 0;
934 + while (environ[pos] && !match_env_var(environ[pos], r))
935 + pos++;
936 + if (!(new = environ[pos]))
937 + return;
938 + }
939 +
940 + // Add it at the end of the array
941 + env[(*env_sizep)++] = new;
942 + env[*env_sizep] = NULL;
943 + }
944 +
945 + static char **
946 + setup_environment(void)
947 + {
948 + // Link built-in rules with user rules
949 + for (int i=ARRAY_SIZE(default_env_rules)-1; i >= 0; i--)
950 + {
951 + default_env_rules[i].next = first_env_rule;
952 + first_env_rule = &default_env_rules[i];
953 + }
954 +
955 + // Scan the original environment
956 + char **orig_env = environ;
957 + int orig_size = 0;
958 + while (orig_env[orig_size])
959 + orig_size++;
960 +
961 + // For each rule, reserve one more slot and calculate length
962 + int num_rules = 0;
963 + for (struct env_rule *r = first_env_rule; r; r=r->next)
964 + {
965 + num_rules++;
966 + r->var_len = strlen(r->var);
967 + }
968 +
969 + // Create a new environment
970 + char **env = xmalloc((orig_size + num_rules + 1) * sizeof(char *));
971 + int size;
972 + if (pass_environ)
973 + {
974 + memcpy(env, environ, orig_size * sizeof(char *));
975 + size = orig_size;
976 + }
977 + else
978 + size = 0;
979 + env[size] = NULL;
980 +
981 + // Apply the rules one by one
982 + for (struct env_rule *r = first_env_rule; r; r=r->next)
983 + apply_env_rule(env, &size, r);
984 +
985 + // Return the new env and pass some gossip
986 + if (verbose > 1)
987 + {
988 + fprintf(stderr, "Passing environment:\n");
989 + for (int i=0; env[i]; i++)
990 + fprintf(stderr, "\t%s\n", env[i]);
991 + }
992 + return env;
993 + }
994 +
995 + /*** Low-level parsing of syscalls ***/
996 +
997 + #ifdef CONFIG_BOX_KERNEL_AMD64
998 + typedef uint64_t arg_t;
999 + #else
1000 + typedef uint32_t arg_t;
1001 + #endif
1002 +
1003 + struct syscall_args {
1004 + arg_t sys;
1005 + arg_t arg1, arg2, arg3;
1006 + arg_t result;
1007 + struct user user;
1008 + };
1009 +
1010 + static int user_mem_fd;
1011 +
1012 + static int read_user_mem(arg_t addr, char *buf, int len)
1013 + {
1014 + if (!user_mem_fd)
1015 + {
1016 + char memname[64];
1017 + sprintf(memname, "/proc/%d/mem", (int) box_pid);
1018 + user_mem_fd = open(memname, O_RDONLY);
1019 + if (user_mem_fd < 0)
1020 + die("open(%s): %m", memname);
1021 + }
1022 + if (lseek64(user_mem_fd, addr, SEEK_SET) < 0)
1023 + die("lseek64(mem): %m");
1024 + return read(user_mem_fd, buf, len);
1025 + }
1026 +
1027 + static void close_user_mem(void)
1028 + {
1029 + if (user_mem_fd)
1030 + {
1031 + close(user_mem_fd);
1032 + user_mem_fd = 0;
1033 + }
1034 + }
1035 +
1036 + #ifdef CONFIG_BOX_KERNEL_AMD64
1037 +
1038 + static void
1039 + get_syscall_args(struct syscall_args *a, int is_exit)
1040 + {
1041 + if (ptrace(PTRACE_GETREGS, box_pid, NULL, &a->user) < 0)
1042 + die("ptrace(PTRACE_GETREGS): %m");
1043 + a->sys = a->user.regs.orig_rax;
1044 + a->result = a->user.regs.rax;
1045 +
1046 + /*
1047 + * CAVEAT: We have to check carefully that this is a real 64-bit syscall.
1048 + * We test whether the process runs in 64-bit mode, but surprisingly this
1049 + * is not enough: a 64-bit process can still issue the INT 0x80 instruction
1050 + * which performs a 32-bit syscall. Currently, the only known way how to
1051 + * detect this situation is to inspect the instruction code (the kernel
1052 + * keeps a syscall type flag internally, but it is not accessible from
1053 + * user space). Hopefully, there is no instruction whose suffix is the
1054 + * code of the SYSCALL instruction. Sometimes, one would wish the
1055 + * instruction codes to be unique even when read backwards :)
1056 + */
1057 +
1058 + if (is_exit)
1059 + return;
1060 +
1061 + int sys_type;
1062 + uint16_t instr;
1063 +
1064 + switch (a->user.regs.cs)
1065 + {
1066 + case 0x23:
1067 + // 32-bit CPU mode => only 32-bit syscalls can be issued
1068 + sys_type = 32;
1069 + break;
1070 + case 0x33:
1071 + // 64-bit CPU mode
1072 + if (read_user_mem(a->user.regs.rip-2, (char *) &instr, 2) != 2)
1073 + err("FO: Cannot read syscall instruction");
1074 + switch (instr)
1075 + {
1076 + case 0x050f:
1077 + break;
1078 + case 0x80cd:
1079 + err("FO: Forbidden 32-bit syscall in 64-bit mode");
1080 + default:
1081 + err("XX: Unknown syscall instruction %04x", instr);
1082 + }
1083 + sys_type = 64;
1084 + break;
1085 + default:
1086 + err("XX: Unknown code segment %04jx", (intmax_t) a->user.regs.cs);
1087 + }
1088 +
1089 + #ifdef CONFIG_BOX_USER_AMD64
1090 + if (sys_type != 64)
1091 + err("FO: Forbidden %d-bit mode syscall", sys_type);
1092 + #else
1093 + if (sys_type != (exec_seen ? 32 : 64))
1094 + err("FO: Forbidden %d-bit mode syscall", sys_type);
1095 + #endif
1096 +
1097 + if (sys_type == 32)
1098 + {
1099 + a->arg1 = a->user.regs.rbx;
1100 + a->arg2 = a->user.regs.rcx;
1101 + a->arg3 = a->user.regs.rdx;
1102 + }
1103 + else
1104 + {
1105 + a->arg1 = a->user.regs.rdi;
1106 + a->arg2 = a->user.regs.rsi;
1107 + a->arg3 = a->user.regs.rdx;
1108 + }
1109 + }
1110 +
1111 + static void
1112 + set_syscall_nr(struct syscall_args *a, arg_t sys)
1113 + {
1114 + a->sys = sys;
1115 + a->user.regs.orig_rax = sys;
1116 + if (ptrace(PTRACE_SETREGS, box_pid, NULL, &a->user) < 0)
1117 + die("ptrace(PTRACE_SETREGS): %m");
1118 + }
1119 +
1120 + static void
1121 + sanity_check(void)
1122 + {
1123 + }
1124 +
1125 + #else
1126 +
1127 + static void
1128 + get_syscall_args(struct syscall_args *a, int is_exit UNUSED)
1129 + {
1130 + if (ptrace(PTRACE_GETREGS, box_pid, NULL, &a->user) < 0)
1131 + die("ptrace(PTRACE_GETREGS): %m");
1132 + a->sys = a->user.regs.orig_eax;
1133 + a->arg1 = a->user.regs.ebx;
1134 + a->arg2 = a->user.regs.ecx;
1135 + a->arg3 = a->user.regs.edx;
1136 + a->result = a->user.regs.eax;
1137 + }
1138 +
1139 + static void
1140 + set_syscall_nr(struct syscall_args *a, arg_t sys)
1141 + {
1142 + a->sys = sys;
1143 + a->user.regs.orig_eax = sys;
1144 + if (ptrace(PTRACE_SETREGS, box_pid, NULL, &a->user) < 0)
1145 + die("ptrace(PTRACE_SETREGS): %m");
1146 + }
1147 +
1148 + static void
1149 + sanity_check(void)
1150 + {
1151 + #if !defined(CONFIG_BOX_ALLOW_INSECURE)
1152 + struct utsname uts;
1153 + if (uname(&uts) < 0)
1154 + die("uname() failed: %m");
1155 +
1156 + if (!strcmp(uts.machine, "x86_64"))
1157 + die("Running 32-bit sandbox on 64-bit kernels is inherently unsafe. Please get a 64-bit version.");
1158 + #endif
1159 + }
1160 +
1161 + #endif
1162 +
1163 + /*** Syscall checks ***/
1164 +
1165 + static void
1166 + valid_filename(arg_t addr)
1167 + {
1168 + char namebuf[4096], *p, *end;
1169 +
1170 + if (!file_access)
1171 + err("FA: File access forbidden");
1172 + if (file_access >= 9)
1173 + return;
1174 +
1175 + p = end = namebuf;
1176 + do
1177 + {
1178 + if (p >= end)
1179 + {
1180 + int remains = PAGE_SIZE - (addr & (PAGE_SIZE-1));
1181 + int l = namebuf + sizeof(namebuf) - end;
1182 + if (l > remains)
1183 + l = remains;
1184 + if (!l)
1185 + err("FA: Access to file with name too long");
1186 + remains = read_user_mem(addr, end, l);
1187 + if (remains < 0)
1188 + die("read(mem): %m");
1189 + if (!remains)
1190 + err("FA: Access to file with name out of memory");
1191 + end += remains;
1192 + addr += remains;
1193 + }
1194 + }
1195 + while (*p++);
1196 +
1197 + msg("[%s] ", namebuf);
1198 + if (file_access >= 3)
1199 + return;
1200 +
1201 + // Everything in current directory is permitted
1202 + if (!strchr(namebuf, '/') && strcmp(namebuf, ".."))
1203 + return;
1204 +
1205 + // ".." anywhere in the path is forbidden
1206 + enum action act = A_DEFAULT;
1207 + if (strstr(namebuf, ".."))
1208 + act = A_NO;
1209 +
1210 + // Scan user rules
1211 + for (struct path_rule *r = user_path_rules; r && !act; r=r->next)
1212 + act = match_path_rule(r, namebuf);
1213 +
1214 + // Scan built-in rules
1215 + if (file_access >= 2)
1216 + for (int i=0; i<ARRAY_SIZE(default_path_rules) && !act; i++)
1217 + act = match_path_rule(&default_path_rules[i], namebuf);
1218 +
1219 + if (act != A_YES)
1220 + err("FA: Forbidden access to file `%s'", namebuf);
1221 + }
1222 +
1223 + // Check syscall. If invalid, return -1, otherwise return the action mask.
1224 + static int
1225 + valid_syscall(struct syscall_args *a)
1226 + {
1227 + unsigned int sys = a->sys;
1228 + unsigned int act = (sys < NUM_ACTIONS) ? syscall_action[sys] : A_DEFAULT;
1229 +
1230 + if (act & A_LIBERAL)
1231 + {
1232 + if (filter_syscalls != 1)
1233 + act = A_DEFAULT;
1234 + }
1235 +
1236 + switch (act & A_ACTION_MASK)
1237 + {
1238 + case A_YES:
1239 + return act;
1240 + case A_NO:
1241 + return -1;
1242 + case A_FILENAME:
1243 + valid_filename(a->arg1);
1244 + return act;
1245 + default: ;
1246 + }
1247 +
1248 + switch (sys)
1249 + {
1250 + case __NR_kill:
1251 + if (a->arg1 == (arg_t) box_pid)
1252 + {
1253 + meta_printf("exitsig:%d\n", (int) a->arg2);
1254 + err("SG: Committed suicide by signal %d", (int) a->arg2);
1255 + }
1256 + return -1;
1257 + case __NR_tgkill:
1258 + if (a->arg1 == (arg_t) box_pid && a->arg2 == (arg_t) box_pid)
1259 + {
1260 + meta_printf("exitsig:%d\n", (int) a->arg3);
1261 + err("SG: Committed suicide by signal %d", (int) a->arg3);
1262 + }
1263 + return -1;
1264 + default:
1265 + return -1;
1266 + }
1267 + }
1268 +
1269 + static void
1270 + signal_alarm(int unused UNUSED)
1271 + {
1272 + /* Time limit checks are synchronous, so we only schedule them there. */
1273 + timer_tick = 1;
1274 + alarm(1);
1275 + }
1276 +
1277 + static void
1278 + signal_int(int unused UNUSED)
1279 + {
1280 + /* Interrupts are fatal, so no synchronization requirements. */
1281 + meta_printf("exitsig:%d\n", SIGINT);
1282 + err("SG: Interrupted");
1283 + }
1284 +
1285 + #define PROC_BUF_SIZE 4096
1286 + static void
1287 + read_proc_file(char *buf, char *name, int *fdp)
1288 + {
1289 + int c;
1290 +
1291 + if (!*fdp)
1292 + {
1293 + sprintf(buf, "/proc/%d/%s", (int) box_pid, name);
1294 + *fdp = open(buf, O_RDONLY);
1295 + if (*fdp < 0)
1296 + die("open(%s): %m", buf);
1297 + }
1298 + lseek(*fdp, 0, SEEK_SET);
1299 + if ((c = read(*fdp, buf, PROC_BUF_SIZE-1)) < 0)
1300 + die("read on /proc/$pid/%s: %m", name);
1301 + if (c >= PROC_BUF_SIZE-1)
1302 + die("/proc/$pid/%s too long", name);
1303 + buf[c] = 0;
1304 + }
1305 +
1306 + static void
1307 + check_timeout(void)
1308 + {
1309 + if (wall_timeout)
1310 + {
1311 + struct timeval now, wall;
1312 + int wall_ms;
1313 + gettimeofday(&now, NULL);
1314 + timersub(&now, &start_time, &wall);
1315 + wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000;
1316 + if (wall_ms > wall_timeout)
1317 + err("TO: Time limit exceeded (wall clock)");
1318 + if (verbose > 1)
1319 + fprintf(stderr, "[wall time check: %d msec]\n", wall_ms);
1320 + }
1321 + if (timeout)
1322 + {
1323 + char buf[PROC_BUF_SIZE], *x;
1324 + int utime, stime, ms;
1325 + static int proc_stat_fd;
1326 + read_proc_file(buf, "stat", &proc_stat_fd);
1327 + x = buf;
1328 + while (*x && *x != ' ')
1329 + x++;
1330 + while (*x == ' ')
1331 + x++;
1332 + if (*x++ != '(')
1333 + die("proc stat syntax error 1");
1334 + while (*x && (*x != ')' || x[1] != ' '))
1335 + x++;
1336 + while (*x == ')' || *x == ' ')
1337 + x++;
1338 + if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
1339 + die("proc stat syntax error 2");
1340 + ms = (utime + stime) * 1000 / ticks_per_sec;
1341 + if (verbose > 1)
1342 + fprintf(stderr, "[time check: %d msec]\n", ms);
1343 + if (ms > timeout && ms > extra_timeout)
1344 + err("TO: Time limit exceeded");
1345 + }
1346 + }
1347 +
1348 + static void
1349 + sample_mem_peak(void)
1350 + {
1351 + /*
1352 + * We want to find out the peak memory usage of the process, which is
1353 + * maintained by the kernel, but unforunately it gets lost when the
1354 + * process exits (it is not reported in struct rusage). Therefore we
1355 + * have to sample it whenever we suspect that the process is about
1356 + * to exit.
1357 + */
1358 + char buf[PROC_BUF_SIZE], *x;
1359 + static int proc_status_fd;
1360 + read_proc_file(buf, "status", &proc_status_fd);
1361 +
1362 + x = buf;
1363 + while (*x)
1364 + {
1365 + char *key = x;
1366 + while (*x && *x != ':' && *x != '\n')
1367 + x++;
1368 + if (!*x || *x == '\n')
1369 + break;
1370 + *x++ = 0;
1371 + while (*x == ' ' || *x == '\t')
1372 + x++;
1373 +
1374 + char *val = x;
1375 + while (*x && *x != '\n')
1376 + x++;
1377 + if (!*x)
1378 + break;
1379 + *x++ = 0;
1380 +
1381 + if (!strcmp(key, "VmPeak"))
1382 + {
1383 + int peak = atoi(val);
1384 + if (peak > mem_peak_kb)
1385 + mem_peak_kb = peak;
1386 + }
1387 + }
1388 +
1389 + if (verbose > 1)
1390 + msg("[mem-peak: %u KB]\n", mem_peak_kb);
1391 + }
1392 +
1393 + static void
1394 + boxkeeper(void)
1395 + {
1396 + int syscall_count = (filter_syscalls ? 0 : 1);
1397 + struct sigaction sa;
1398 +
1399 + is_ptraced = 1;
1400 +
1401 + bzero(&sa, sizeof(sa));
1402 + sa.sa_handler = signal_int;
1403 + sigaction(SIGINT, &sa, NULL);
1404 +
1405 + gettimeofday(&start_time, NULL);
1406 + ticks_per_sec = sysconf(_SC_CLK_TCK);
1407 + if (ticks_per_sec <= 0)
1408 + die("Invalid ticks_per_sec!");
1409 +
1410 + if (timeout || wall_timeout)
1411 + {
1412 + sa.sa_handler = signal_alarm;
1413 + sigaction(SIGALRM, &sa, NULL);
1414 + alarm(1);
1415 + }
1416 +
1417 + for(;;)
1418 + {
1419 + struct rusage rus;
1420 + int stat;
1421 + pid_t p;
1422 + if (timer_tick)
1423 + {
1424 + check_timeout();
1425 + timer_tick = 0;
1426 + }
1427 + p = wait4(box_pid, &stat, WUNTRACED, &rus);
1428 + if (p < 0)
1429 + {
1430 + if (errno == EINTR)
1431 + continue;
1432 + die("wait4: %m");
1433 + }
1434 + if (p != box_pid)
1435 + die("wait4: unknown pid %d exited!", p);
1436 + if (WIFEXITED(stat))
1437 + {
1438 + box_pid = 0;
1439 + final_stats(&rus);
1440 + if (WEXITSTATUS(stat))
1441 + {
1442 + if (syscall_count)
1443 + {
1444 + meta_printf("exitcode:%d\n", WEXITSTATUS(stat));
1445 + err("RE: Exited with error status %d", WEXITSTATUS(stat));
1446 + }
1447 + else
1448 + {
1449 + // Internal error happened inside the child process and it has been already reported.
1450 + box_exit(2);
1451 + }
1452 + }
1453 + if (timeout && total_ms > timeout)
1454 + err("TO: Time limit exceeded");
1455 + if (wall_timeout && wall_ms > wall_timeout)
1456 + err("TO: Time limit exceeded (wall clock)");
1457 + flush_line();
1458 + fprintf(stderr,"OK\n");
1459 + box_exit(0);
1460 + }
1461 + if (WIFSIGNALED(stat))
1462 + {
1463 + box_pid = 0;
1464 + meta_printf("exitsig:%d\n", WTERMSIG(stat));
1465 + final_stats(&rus);
1466 + err("SG: Caught fatal signal %d%s", WTERMSIG(stat), (syscall_count ? "" : " during startup"));
1467 + }
1468 + if (WIFSTOPPED(stat))
1469 + {
1470 + int sig = WSTOPSIG(stat);
1471 + if (sig == SIGTRAP)
1472 + {
1473 + if (verbose > 2)
1474 + msg("[ptrace status %08x] ", stat);
1475 + static int stop_count;
1476 + if (!stop_count++) /* Traceme request */
1477 + msg(">> Traceme request caught\n");
1478 + else
1479 + err("SG: Breakpoint");
1480 + ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1481 + }
1482 + else if (sig == (SIGTRAP | 0x80))
1483 + {
1484 + if (verbose > 2)
1485 + msg("[ptrace status %08x] ", stat);
1486 + struct syscall_args a;
1487 + static unsigned int sys_tick, last_act;
1488 + static arg_t last_sys;
1489 + if (++sys_tick & 1) /* Syscall entry */
1490 + {
1491 + char namebuf[32];
1492 + int act;
1493 +
1494 + get_syscall_args(&a, 0);
1495 + arg_t sys = a.sys;
1496 + msg(">> Syscall %-12s (%08jx,%08jx,%08jx) ", syscall_name(sys, namebuf), (intmax_t) a.arg1, (intmax_t) a.arg2, (intmax_t) a.arg3);
1497 + if (!exec_seen)
1498 + {
1499 + msg("[master] ");
1500 + if (sys == NATIVE_NR_execve)
1501 + {
1502 + exec_seen = 1;
1503 + close_user_mem();
1504 + }
1505 + }
1506 + else if ((act = valid_syscall(&a)) >= 0)
1507 + {
1508 + last_act = act;
1509 + syscall_count++;
1510 + if (act & A_SAMPLE_MEM)
1511 + sample_mem_peak();
1512 + }
1513 + else
1514 + {
1515 + /*
1516 + * Unfortunately, PTRACE_KILL kills _after_ the syscall completes,
1517 + * so we have to change it to something harmless (e.g., an undefined
1518 + * syscall) and make the program continue.
1519 + */
1520 + set_syscall_nr(&a, ~(arg_t)0);
1521 + err("FO: Forbidden syscall %s", syscall_name(sys, namebuf));
1522 + }
1523 + last_sys = sys;
1524 + }
1525 + else /* Syscall return */
1526 + {
1527 + get_syscall_args(&a, 1);
1528 + if (a.sys == ~(arg_t)0)
1529 + {
1530 + /* Some syscalls (sigreturn et al.) do not return a value */
1531 + if (!(last_act & A_NO_RETVAL))
1532 + err("XX: Syscall does not return, but it should");
1533 + }
1534 + else
1535 + {
1536 + if (a.sys != last_sys)
1537 + err("XX: Mismatched syscall entry/exit");
1538 + }
1539 + if (last_act & A_NO_RETVAL)
1540 + msg("= ?\n");
1541 + else
1542 + msg("= %jd\n", (intmax_t) a.result);
1543 + }
1544 + ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1545 + }
1546 + else if (sig == SIGSTOP)
1547 + {
1548 + msg(">> SIGSTOP\n");
1549 + if (ptrace(PTRACE_SETOPTIONS, box_pid, NULL, (void *) PTRACE_O_TRACESYSGOOD) < 0)
1550 + die("ptrace(PTRACE_SETOPTIONS): %m");
1551 + ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1552 + }
1553 + else if (sig != SIGXCPU && sig != SIGXFSZ)
1554 + {
1555 + msg(">> Signal %d\n", sig);
1556 + sample_mem_peak(); /* Signal might be fatal, so update mem-peak */
1557 + ptrace(PTRACE_SYSCALL, box_pid, 0, sig);
1558 + }
1559 + else
1560 + {
1561 + meta_printf("exitsig:%d", sig);
1562 + err("SG: Received signal %d", sig);
1563 + }
1564 + }
1565 + else
1566 + die("wait4: unknown status %x, giving up!", stat);
1567 + }
1568 + }
1569 +
1570 + static void
1571 + box_inside(int argc, char **argv)
1572 + {
1573 + struct rlimit rl;
1574 + char *args[argc+1];
1575 +
1576 + memcpy(args, argv, argc * sizeof(char *));
1577 + args[argc] = NULL;
1578 + if (set_cwd && chdir(set_cwd))
1579 + die("chdir: %m");
1580 + if (redir_stdin)
1581 + {
1582 + close(0);
1583 + if (open(redir_stdin, O_RDONLY) != 0)
1584 + die("open(\"%s\"): %m", redir_stdin);
1585 + }
1586 + if (redir_stdout)
1587 + {
1588 + close(1);
1589 + if (open(redir_stdout, O_WRONLY | O_CREAT | O_TRUNC, 0666) != 1)
1590 + die("open(\"%s\"): %m", redir_stdout);
1591 + }
1592 + if (redir_stderr)
1593 + {
1594 + close(2);
1595 + if (open(redir_stderr, O_WRONLY | O_CREAT | O_TRUNC, 0666) != 2)
1596 + die("open(\"%s\"): %m", redir_stderr);
1597 + }
1598 + else
1599 + dup2(1, 2);
1600 + setpgrp();
1601 +
1602 + if (memory_limit)
1603 + {
1604 + rl.rlim_cur = rl.rlim_max = memory_limit * 1024;
1605 + if (setrlimit(RLIMIT_AS, &rl) < 0)
1606 + die("setrlimit(RLIMIT_AS): %m");
1607 + }
1608 +
1609 + rl.rlim_cur = rl.rlim_max = (stack_limit ? (rlim_t)stack_limit * 1024 : RLIM_INFINITY);
1610 + if (setrlimit(RLIMIT_STACK, &rl) < 0)
1611 + die("setrlimit(RLIMIT_STACK): %m");
1612 +
1613 + rl.rlim_cur = rl.rlim_max = 64;
1614 + if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
1615 + die("setrlimit(RLIMIT_NOFILE): %m");
1616 +
1617 + char **env = setup_environment();
1618 + if (filter_syscalls)
1619 + {
1620 + if (ptrace(PTRACE_TRACEME) < 0)
1621 + die("ptrace(PTRACE_TRACEME): %m");
1622 + /* Trick: Make sure that we are stopped until the boxkeeper wakes up. */
1623 + raise(SIGSTOP);
1624 + }
1625 + execve(args[0], args, env);
1626 + die("execve(\"%s\"): %m", args[0]);
1627 + }
1628 +
1629 + static void
1630 + usage(void)
1631 + {
1632 + fprintf(stderr, "Invalid arguments!\n");
1633 + printf("\
1634 + Usage: box [<options>] -- <command> <arguments>\n\
1635 + \n\
1636 + Options:\n\
1637 + -a <level>\tSet file access level (0=none, 1=cwd, 2=/etc,/lib,..., 3=whole fs, 9=no checks; needs -f)\n\
1638 + -c <dir>\tChange directory to <dir> first\n\
1639 + -e\t\tInherit full environment of the parent process\n\
1640 + -E <var>\tInherit the environment variable <var> from the parent process\n\
1641 + -E <var>=<val>\tSet the environment variable <var> to <val>; unset it if <var> is empty\n\
1642 + -f\t\tFilter system calls (-ff=very restricted)\n\
1643 + -i <file>\tRedirect stdin from <file>\n\
1644 + -k <size>\tLimit stack size to <size> KB (default: 0=unlimited)\n\
1645 + -m <size>\tLimit address space to <size> KB\n\
1646 + -M <file>\tOutput process information to <file> (name:value)\n\
1647 + -o <file>\tRedirect stdout to <file>\n\
1648 + -p <path>\tPermit access to the specified path (or subtree if it ends with a `/')\n\
1649 + -p <path>=<act>\tDefine action for the specified path (<act>=yes/no)\n\
1650 + -r <file>\tRedirect stderr to <file>\n\
1651 + -s <sys>\tPermit the specified syscall (be careful)\n\
1652 + -s <sys>=<act>\tDefine action for the specified syscall (<act>=yes/no/file)\n\
1653 + -t <time>\tSet run time limit (seconds, fractions allowed)\n\
1654 + -T\t\tAllow syscalls for measuring run time\n\
1655 + -v\t\tBe verbose (use multiple times for even more verbosity)\n\
1656 + -w <time>\tSet wall clock time limit (seconds, fractions allowed)\n\
1657 + -x <time>\tSet extra timeout, before which a timing-out program is not yet killed,\n\
1658 + \t\tso that its real execution time is reported (seconds, fractions allowed)\n\
1659 + -A <opt>\tPass <opt> as additional argument to the <command>\n\
1660 + \t\tBe noted that this option will be appended after <arguments> respectively\n\
1661 + ");
1662 + exit(2);
1663 + }
1664 +
1665 + int
1666 + main(int argc, char **argv)
1667 + {
1668 + int c;
1669 + uid_t uid;
1670 + char **prog_argv = xmalloc(sizeof(char*) * argc);
1671 + int prog_argc = 0;
1672 +
1673 + while ((c = getopt(argc, argv, "a:c:eE:fi:k:m:M:o:p:r:s:t:Tvw:x:A:")) >= 0)
1674 + switch (c)
1675 + {
1676 + case 'a':
1677 + file_access = atol(optarg);
1678 + break;
1679 + case 'c':
1680 + set_cwd = optarg;
1681 + break;
1682 + case 'e':
1683 + pass_environ = 1;
1684 + break;
1685 + case 'E':
1686 + if (!set_env_action(optarg))
1687 + usage();
1688 + break;
1689 + case 'f':
1690 + filter_syscalls++;
1691 + break;
1692 + case 'k':
1693 + stack_limit = atol(optarg);
1694 + break;
1695 + case 'i':
1696 + redir_stdin = optarg;
1697 + break;
1698 + case 'm':
1699 + memory_limit = atol(optarg);
1700 + break;
1701 + case 'M':
1702 + meta_open(optarg);
1703 + break;
1704 + case 'o':
1705 + redir_stdout = optarg;
1706 + break;
1707 + case 'p':
1708 + if (!set_path_action(optarg))
1709 + usage();
1710 + break;
1711 + case 'r':
1712 + redir_stderr = optarg;
1713 + break;
1714 + case 's':
1715 + if (!set_syscall_action(optarg))
1716 + usage();
1717 + break;
1718 + case 't':
1719 + timeout = 1000*atof(optarg);
1720 + break;
1721 + case 'T':
1722 + syscall_action[__NR_times] = A_YES;
1723 + break;
1724 + case 'v':
1725 + verbose++;
1726 + break;
1727 + case 'w':
1728 + wall_timeout = 1000*atof(optarg);
1729 + break;
1730 + case 'x':
1731 + extra_timeout = 1000*atof(optarg);
1732 + case 'A':
1733 + prog_argv[prog_argc++] = strdup(optarg);
1734 + break;
1735 + break;
1736 + default:
1737 + usage();
1738 + }
1739 + if (optind >= argc)
1740 + usage();
1741 +
1742 + sanity_check();
1743 + uid = geteuid();
1744 + if (setreuid(uid, uid) < 0)
1745 + die("setreuid: %m");
1746 + box_pid = fork();
1747 + if (box_pid < 0)
1748 + die("fork: %m");
1749 + if (!box_pid) {
1750 + int real_argc = prog_argc + argc - optind;
1751 + char **real_argv = xmalloc(sizeof(char*) * (real_argc));
1752 + for (int i = 0;i < argc-optind;i++)
1753 + real_argv[i] = strdup(argv[i+optind]);
1754 + for (int i = 0;i < prog_argc;i++)
1755 + real_argv[argc - optind + i] = strdup(prog_argv[i]);
1756 + box_inside(real_argc, real_argv);
1757 + } else
1758 + boxkeeper();
1759 + die("Internal error: fell over edge of the world");
1760 + }
You need to be logged in to leave comments. Login now