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