Description:
added /dev/urandom to file allowed to be accessed, probably needed after ubuntu 9.04 git-svn-id: http://theory.cpe.ku.ac.th/grader/judge/trunk/scripts@417 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r76:4469d653fe5f - - 1 file changed: 1 inserted, 0 deleted

@@ -1,381 +1,382
1 1 /*
2 2 * A Simple Testing Sandbox
3 3 *
4 4 * (c) 2001--2004 Martin Mares <mj@ucw.cz>
5 5 */
6 6
7 7 #define _LARGEFILE64_SOURCE
8 8 //#define _GNU_SOURCE
9 9
10 10 #include <errno.h>
11 11 #include <stdio.h>
12 12 #include <fcntl.h>
13 13 #include <stdlib.h>
14 14 #include <string.h>
15 15 #include <stdarg.h>
16 16 #include <unistd.h>
17 17 #include <getopt.h>
18 18 #include <time.h>
19 19 #include <sys/wait.h>
20 20 #include <sys/user.h>
21 21 #include <sys/time.h>
22 22 #include <sys/ptrace.h>
23 23 #include <sys/signal.h>
24 24 #include <sys/sysinfo.h>
25 25 #include <sys/syscall.h>
26 26 #include <sys/resource.h>
27 27
28 28 #define NONRET __attribute__((noreturn))
29 29 #define UNUSED __attribute__((unused))
30 30
31 31 static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */
32 32 static double timeout;
33 33 static int pass_environ;
34 34 static int use_wall_clock;
35 35 static int file_access;
36 36 static int verbose;
37 37 static int memory_limit;
38 38 static int allow_times;
39 39 static char *redir_stdin, *redir_stdout;
40 40 static char *set_cwd;
41 41
42 42 static pid_t box_pid;
43 43 static int is_ptraced;
44 44 static volatile int timer_tick;
45 45 static time_t start_time;
46 46 static int ticks_per_sec;
47 47 static int page_size;
48 48
49 49 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0
50 50 /* glibc 2.1 or newer -> has lseek64 */
51 51 #define long_seek(f,o,w) lseek64(f,o,w)
52 52 #else
53 53 /* Touching clandestine places in glibc */
54 54 extern loff_t llseek(int fd, loff_t pos, int whence);
55 55 #define long_seek(f,o,w) llseek(f,o,w)
56 56 #endif
57 57
58 58 int max_mem_used = 0;
59 59
60 60 void print_running_stat(double wall_time,
61 61 double user_time,
62 62 double system_time,
63 63 int mem_usage)
64 64 {
65 65 fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dm\n",
66 66 wall_time, user_time, system_time, mem_usage);
67 67 }
68 68
69 69 static void NONRET
70 70 box_exit(void)
71 71 {
72 72 if (box_pid > 0) {
73 73 if (is_ptraced)
74 74 ptrace(PTRACE_KILL, box_pid);
75 75 kill(-box_pid, SIGKILL);
76 76 kill(box_pid, SIGKILL);
77 77 }
78 78
79 79 struct timeval total;
80 80 int wall;
81 81 struct rusage rus;
82 82 int stat;
83 83 pid_t p;
84 84
85 85 // wait so that we can get information
86 86 p = wait4(box_pid, &stat, WUNTRACED, &rus);
87 87 if (p < 0) {
88 88 fprintf(stderr,"wait4: error\n");
89 89 print_running_stat(0,0,0,max_mem_used);
90 90 } else if (p != box_pid) {
91 91 fprintf(stderr,"wait4: unknown pid %d exited!\n", p);
92 92 print_running_stat(0,0,0,max_mem_used);
93 93 } else {
94 94 if (!WIFEXITED(stat))
95 95 fprintf(stderr,"wait4: unknown status\n");
96 96 struct timeval total;
97 97 int wall;
98 98 wall = time(NULL) - start_time;
99 99 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
100 100
101 101 print_running_stat((double)wall,
102 102 (double) rus.ru_utime.tv_sec +
103 103 ((double) rus.ru_utime.tv_usec/1000000.0),
104 104 (double) rus.ru_stime.tv_sec +
105 105 ((double) rus.ru_stime.tv_usec/1000000.0),
106 106 max_mem_used);
107 107 }
108 108 exit(1);
109 109 }
110 110
111 111 static void NONRET __attribute__((format(printf,1,2)))
112 112 die(char *msg, ...)
113 113 {
114 114 va_list args;
115 115 va_start(args, msg);
116 116 vfprintf(stderr, msg, args);
117 117 fputc('\n', stderr);
118 118 box_exit();
119 119 }
120 120
121 121 static void __attribute__((format(printf,1,2)))
122 122 log(char *msg, ...)
123 123 {
124 124 va_list args;
125 125 va_start(args, msg);
126 126 if (verbose)
127 127 {
128 128 vfprintf(stderr, msg, args);
129 129 fflush(stderr);
130 130 }
131 131 va_end(args);
132 132 }
133 133
134 134 static void
135 135 valid_filename(unsigned long addr)
136 136 {
137 137 char namebuf[4096], *p, *end;
138 138 static int mem_fd;
139 139
140 140 if (!file_access)
141 141 die("File access forbidden.");
142 142 if (file_access >= 9)
143 143 return;
144 144
145 145 if (!mem_fd)
146 146 {
147 147 sprintf(namebuf, "/proc/%d/mem", (int) box_pid);
148 148 mem_fd = open(namebuf, O_RDONLY);
149 149 if (mem_fd < 0)
150 150 die("open(%s): %m", namebuf);
151 151 }
152 152 p = end = namebuf;
153 153 do
154 154 {
155 155 if (p >= end)
156 156 {
157 157 int remains = PAGE_SIZE - (addr & (PAGE_SIZE-1));
158 158 int l = namebuf + sizeof(namebuf) - end;
159 159 if (l > remains)
160 160 l = remains;
161 161 if (!l)
162 162 die("Access to file with name too long.");
163 163 if (long_seek(mem_fd, addr, SEEK_SET) < 0)
164 164 die("long_seek(mem): %m");
165 165 remains = read(mem_fd, end, l);
166 166 if (remains < 0)
167 167 die("read(mem): %m");
168 168 if (!remains)
169 169 die("Access to file with name out of memory.");
170 170 end += l;
171 171 addr += l;
172 172 }
173 173 }
174 174 while (*p++);
175 175
176 176 log("[%s] ", namebuf);
177 177 if (file_access >= 3)
178 178 return;
179 179 if (!strchr(namebuf, '/') && strcmp(namebuf, ".."))
180 180 return;
181 181 if (file_access >= 2)
182 182 {
183 183 if ((!strncmp(namebuf, "/etc/", 5) ||
184 184 !strncmp(namebuf, "/lib/", 5) ||
185 185 !strncmp(namebuf, "/usr/lib/", 9))
186 186 && !strstr(namebuf, ".."))
187 187 return;
188 188 if (!strcmp(namebuf, "/dev/null") ||
189 189 !strcmp(namebuf, "/dev/zero") ||
190 + !strcmp(namebuf, "/dev/urandom") ||
190 191 !strcmp(namebuf, "/proc/meminfo") ||
191 192 !strcmp(namebuf, "/proc/self/stat") ||
192 193 !strncmp(namebuf, "/usr/share/zoneinfo/", 20))
193 194 return;
194 195 }
195 196 die("Forbidden access to file `%s'.", namebuf);
196 197 }
197 198
198 199 static int
199 200 valid_syscall(struct user *u)
200 201 {
201 202 switch (u->regs.orig_eax)
202 203 {
203 204 case __NR_execve:
204 205 {
205 206 static int exec_counter;
206 207 return !exec_counter++;
207 208 }
208 209 case __NR_open:
209 210 case __NR_creat:
210 211 case __NR_unlink:
211 212 case __NR_oldstat:
212 213 case __NR_access:
213 214 case __NR_oldlstat:
214 215 case __NR_truncate:
215 216 case __NR_stat:
216 217 case __NR_lstat:
217 218 case __NR_truncate64:
218 219 case __NR_stat64:
219 220 case __NR_lstat64:
220 221 valid_filename(u->regs.ebx);
221 222 return 1;
222 223 case __NR_exit:
223 224 case __NR_read:
224 225 case __NR_write:
225 226 case __NR_close:
226 227 case __NR_lseek:
227 228 case __NR_getpid:
228 229 case __NR_getuid:
229 230 case __NR_oldfstat:
230 231 case __NR_dup:
231 232 case __NR_brk:
232 233 case __NR_getgid:
233 234 case __NR_geteuid:
234 235 case __NR_getegid:
235 236 case __NR_dup2:
236 237 case __NR_ftruncate:
237 238 case __NR_fstat:
238 239 case __NR_personality:
239 240 case __NR__llseek:
240 241 case __NR_readv:
241 242 case __NR_writev:
242 243 case __NR_getresuid:
243 244 #ifdef __NR_pread64
244 245 case __NR_pread64:
245 246 case __NR_pwrite64:
246 247 #else
247 248 case __NR_pread:
248 249 case __NR_pwrite:
249 250 #endif
250 251 case __NR_ftruncate64:
251 252 case __NR_fstat64:
252 253 case __NR_fcntl:
253 254 case __NR_fcntl64:
254 255 case __NR_mmap:
255 256 case __NR_munmap:
256 257 case __NR_ioctl:
257 258 case __NR_uname:
258 259 case 252:
259 260 case 243:
260 261 // added for free pascal
261 262 case __NR_ugetrlimit:
262 263 case __NR_readlink:
263 264 return 1;
264 265 // case __NR_time:
265 266 case __NR_alarm:
266 267 // case __NR_pause:
267 268 case __NR_signal:
268 269 case __NR_fchmod:
269 270 case __NR_sigaction:
270 271 case __NR_sgetmask:
271 272 case __NR_ssetmask:
272 273 case __NR_sigsuspend:
273 274 case __NR_sigpending:
274 275 case __NR_getrlimit:
275 276 case __NR_getrusage:
276 277 case __NR_gettimeofday:
277 278 case __NR_select:
278 279 case __NR_readdir:
279 280 case __NR_setitimer:
280 281 case __NR_getitimer:
281 282 case __NR_sigreturn:
282 283 case __NR_mprotect:
283 284 case __NR_sigprocmask:
284 285 case __NR_getdents:
285 286 case __NR_getdents64:
286 287 case __NR__newselect:
287 288 case __NR_fdatasync:
288 289 case __NR_mremap:
289 290 case __NR_poll:
290 291 case __NR_getcwd:
291 292 case __NR_nanosleep:
292 293 case __NR_rt_sigreturn:
293 294 case __NR_rt_sigaction:
294 295 case __NR_rt_sigprocmask:
295 296 case __NR_rt_sigpending:
296 297 case __NR_rt_sigtimedwait:
297 298 case __NR_rt_sigqueueinfo:
298 299 case __NR_rt_sigsuspend:
299 300 case __NR_mmap2:
300 301 case __NR__sysctl:
301 302 return (filter_syscalls == 1);
302 303 case __NR_times:
303 304 case __NR_time:
304 305 return allow_times;
305 306 case __NR_kill:
306 307 if (u->regs.ebx == box_pid)
307 308 die("Commited suicide by signal %d.", (int)u->regs.ecx);
308 309 return 0;
309 310 default:
310 311 return 0;
311 312 }
312 313 }
313 314
314 315 static void
315 316 signal_alarm(int unused UNUSED)
316 317 {
317 318 /* Time limit checks are synchronous, so we only schedule them there. */
318 319 timer_tick = 1;
319 320
320 321 //NOTE: do not use alarm, changed to setitimer for precision
321 322 // alarm(1);
322 323 }
323 324
324 325 static void
325 326 signal_int(int unused UNUSED)
326 327 {
327 328 /* Interrupts are fatal, so no synchronization requirements. */
328 329 die("Interrupted.");
329 330 }
330 331
331 332 static void
332 333 check_timeout(void)
333 334 {
334 335 double sec;
335 336
336 337 if (use_wall_clock)
337 338 sec = (double)(time(NULL) - start_time);
338 339 else
339 340 {
340 341 char buf[4096], *x;
341 342 int c, utime, stime;
342 343 static int proc_status_fd;
343 344 if (!proc_status_fd)
344 345 {
345 346 sprintf(buf, "/proc/%d/stat", (int) box_pid);
346 347 proc_status_fd = open(buf, O_RDONLY);
347 348 if (proc_status_fd < 0)
348 349 die("open(%s): %m", buf);
349 350 }
350 351 lseek(proc_status_fd, 0, SEEK_SET);
351 352 if ((c = read(proc_status_fd, buf, sizeof(buf)-1)) < 0)
352 353 die("read on /proc/$pid/stat: %m");
353 354 if (c >= (int) sizeof(buf) - 1)
354 355 die("/proc/$pid/stat too long");
355 356 buf[c] = 0;
356 357 x = buf;
357 358 while (*x && *x != ' ')
358 359 x++;
359 360 while (*x == ' ')
360 361 x++;
361 362 if (*x++ != '(')
362 363 die("proc syntax error 1");
363 364 while (*x && (*x != ')' || x[1] != ' '))
364 365 x++;
365 366 while (*x == ')' || *x == ' ')
366 367 x++;
367 368 if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
368 369 die("proc syntax error 2");
369 370 //printf("%s - %d\n",x,ticks_per_sec);
370 371 sec = ((double)(utime + stime))/(double)ticks_per_sec;
371 372 }
372 373 if (verbose > 1)
373 374 fprintf(stderr, "[timecheck: %d seconds]\n", sec);
374 375 if (sec > timeout) {
375 376 die("Time limit exceeded.",sec,timeout);
376 377 }
377 378 }
378 379
379 380 static void
380 381 check_memory_usage()
381 382 {
You need to be logged in to leave comments. Login now