Description:
[grader] obsolete new_problem, fixed memory measurement bug in box.cc git-svn-id: http://theory.cpe.ku.ac.th/grader/judge/trunk/scripts@186 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

r49:5746784ead66 - - 2 files changed: 11 inserted, 2 deleted

@@ -1,68 +1,73
1 #!/usr/bin/ruby
1 #!/usr/bin/ruby
2
2
3 # new_problem:
3 # new_problem:
4 # * creates a directory for a problem in the current directory,
4 # * creates a directory for a problem in the current directory,
5 # * create standard testcase config file
5 # * create standard testcase config file
6
6
7 require 'erb'
7 require 'erb'
8
8
9 def process_options(options)
9 def process_options(options)
10 i = 2
10 i = 2
11 while i<ARGV.length
11 while i<ARGV.length
12 if ARGV[i]=='-t'
12 if ARGV[i]=='-t'
13 options[:time_limit] = ARGV[i+1].to_i if ARGV.length>i+1
13 options[:time_limit] = ARGV[i+1].to_i if ARGV.length>i+1
14 i += 1
14 i += 1
15 end
15 end
16 if ARGV[i]=='-m'
16 if ARGV[i]=='-m'
17 options[:mem_limit] = ARGV[i+1].to_i if ARGV.length>i+1
17 options[:mem_limit] = ARGV[i+1].to_i if ARGV.length>i+1
18 i += 1
18 i += 1
19 end
19 end
20 i += 1
20 i += 1
21 end
21 end
22 end
22 end
23
23
24 +
25 + puts "This script is out of dated, shall be fixed soon"
26 + puts "Right now, you can create raw_ev and import"
27 + exit(0)
28 +
24 GRADER_DIR = File.dirname(__FILE__)
29 GRADER_DIR = File.dirname(__FILE__)
25
30
26 # print usage
31 # print usage
27 if ARGV.length < 2
32 if ARGV.length < 2
28 puts <<USAGE
33 puts <<USAGE
29 using: new_problem problem number_of_testcase [options]
34 using: new_problem problem number_of_testcase [options]
30 * creates a directory for a problem in the current directory,
35 * creates a directory for a problem in the current directory,
31 * create standard testcase config file
36 * create standard testcase config file
32 * options: -t time-limit (in seconds)
37 * options: -t time-limit (in seconds)
33 -m mem-limit (in MB)
38 -m mem-limit (in MB)
34 USAGE
39 USAGE
35 exit(127)
40 exit(127)
36 end
41 end
37
42
38 # processing arguments
43 # processing arguments
39 problem = ARGV[0]
44 problem = ARGV[0]
40 num_testcases = ARGV[1].to_i
45 num_testcases = ARGV[1].to_i
41
46
42 options = {:time_limit => 1, :mem_limit => 16}
47 options = {:time_limit => 1, :mem_limit => 16}
43 process_options(options)
48 process_options(options)
44
49
45 # start working
50 # start working
46 puts "creating directories"
51 puts "creating directories"
47
52
48 system("mkdir #{problem}")
53 system("mkdir #{problem}")
49 system("mkdir #{problem}/script")
54 system("mkdir #{problem}/script")
50 system("mkdir #{problem}/test_cases")
55 system("mkdir #{problem}/test_cases")
51
56
52 puts "creating testcases directories"
57 puts "creating testcases directories"
53
58
54 1.upto(num_testcases) do |i|
59 1.upto(num_testcases) do |i|
55 system("mkdir #{problem}/test_cases/#{i}")
60 system("mkdir #{problem}/test_cases/#{i}")
56 end
61 end
57
62
58 # generating all_tests.cfg
63 # generating all_tests.cfg
59 puts "generating testcase config file"
64 puts "generating testcase config file"
60
65
61 - template = File.open(File.dirname(__FILE__) + "/all_tests.cfg.erb").read
66 + template = File.open(File.dirname(__FILE__) + "/templates/all_tests.cfg.erb").read
62 all_test_cfg = ERB.new(template)
67 all_test_cfg = ERB.new(template)
63
68
64 cfg_file = File.open("#{problem}/test_cases/all_tests.cfg","w")
69 cfg_file = File.open("#{problem}/test_cases/all_tests.cfg","w")
65 cfg_file.puts all_test_cfg.result
70 cfg_file.puts all_test_cfg.result
66 cfg_file.close
71 cfg_file.close
67
72
68 puts "done"
73 puts "done"
@@ -1,673 +1,677
1 /*
1 /*
2 * A Simple Testing Sandbox
2 * A Simple Testing Sandbox
3 *
3 *
4 * (c) 2001--2004 Martin Mares <mj@ucw.cz>
4 * (c) 2001--2004 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 #include <errno.h>
10 #include <errno.h>
11 #include <stdio.h>
11 #include <stdio.h>
12 #include <fcntl.h>
12 #include <fcntl.h>
13 #include <stdlib.h>
13 #include <stdlib.h>
14 #include <string.h>
14 #include <string.h>
15 #include <stdarg.h>
15 #include <stdarg.h>
16 #include <unistd.h>
16 #include <unistd.h>
17 #include <getopt.h>
17 #include <getopt.h>
18 #include <time.h>
18 #include <time.h>
19 #include <sys/wait.h>
19 #include <sys/wait.h>
20 #include <sys/user.h>
20 #include <sys/user.h>
21 #include <sys/time.h>
21 #include <sys/time.h>
22 #include <sys/ptrace.h>
22 #include <sys/ptrace.h>
23 #include <sys/signal.h>
23 #include <sys/signal.h>
24 #include <sys/sysinfo.h>
24 #include <sys/sysinfo.h>
25 #include <sys/syscall.h>
25 #include <sys/syscall.h>
26 #include <sys/resource.h>
26 #include <sys/resource.h>
27
27
28 #define NONRET __attribute__((noreturn))
28 #define NONRET __attribute__((noreturn))
29 #define UNUSED __attribute__((unused))
29 #define UNUSED __attribute__((unused))
30
30
31 static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */
31 static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */
32 static int timeout;
32 static int timeout;
33 static int pass_environ;
33 static int pass_environ;
34 static int use_wall_clock;
34 static int use_wall_clock;
35 static int file_access;
35 static int file_access;
36 static int verbose;
36 static int verbose;
37 static int memory_limit;
37 static int memory_limit;
38 static int allow_times;
38 static int allow_times;
39 static char *redir_stdin, *redir_stdout;
39 static char *redir_stdin, *redir_stdout;
40 static char *set_cwd;
40 static char *set_cwd;
41
41
42 static pid_t box_pid;
42 static pid_t box_pid;
43 static int is_ptraced;
43 static int is_ptraced;
44 static volatile int timer_tick;
44 static volatile int timer_tick;
45 static time_t start_time;
45 static time_t start_time;
46 static int ticks_per_sec;
46 static int ticks_per_sec;
47 + static int page_size;
47
48
48 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0
49 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0
49 /* glibc 2.1 or newer -> has lseek64 */
50 /* glibc 2.1 or newer -> has lseek64 */
50 #define long_seek(f,o,w) lseek64(f,o,w)
51 #define long_seek(f,o,w) lseek64(f,o,w)
51 #else
52 #else
52 /* Touching clandestine places in glibc */
53 /* Touching clandestine places in glibc */
53 extern loff_t llseek(int fd, loff_t pos, int whence);
54 extern loff_t llseek(int fd, loff_t pos, int whence);
54 #define long_seek(f,o,w) llseek(f,o,w)
55 #define long_seek(f,o,w) llseek(f,o,w)
55 #endif
56 #endif
56
57
57 int max_mem_used = 0;
58 int max_mem_used = 0;
58
59
59 void print_running_stat(double wall_time,
60 void print_running_stat(double wall_time,
60 double user_time,
61 double user_time,
61 double system_time,
62 double system_time,
62 int mem_usage)
63 int mem_usage)
63 {
64 {
64 fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dm\n",
65 fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dm\n",
65 wall_time, user_time, system_time, mem_usage);
66 wall_time, user_time, system_time, mem_usage);
66 }
67 }
67
68
68 static void NONRET
69 static void NONRET
69 box_exit(void)
70 box_exit(void)
70 {
71 {
71 if (box_pid > 0) {
72 if (box_pid > 0) {
72 if (is_ptraced)
73 if (is_ptraced)
73 ptrace(PTRACE_KILL, box_pid);
74 ptrace(PTRACE_KILL, box_pid);
74 kill(-box_pid, SIGKILL);
75 kill(-box_pid, SIGKILL);
75 kill(box_pid, SIGKILL);
76 kill(box_pid, SIGKILL);
76 }
77 }
77
78
78 struct timeval total;
79 struct timeval total;
79 int wall;
80 int wall;
80 struct rusage rus;
81 struct rusage rus;
81 int stat;
82 int stat;
82 pid_t p;
83 pid_t p;
83
84
84 // wait so that we can get information
85 // wait so that we can get information
85 p = wait4(box_pid, &stat, WUNTRACED, &rus);
86 p = wait4(box_pid, &stat, WUNTRACED, &rus);
86 if (p < 0) {
87 if (p < 0) {
87 fprintf(stderr,"wait4: error\n");
88 fprintf(stderr,"wait4: error\n");
88 print_running_stat(0,0,0,max_mem_used);
89 print_running_stat(0,0,0,max_mem_used);
89 } else if (p != box_pid) {
90 } else if (p != box_pid) {
90 fprintf(stderr,"wait4: unknown pid %d exited!\n", p);
91 fprintf(stderr,"wait4: unknown pid %d exited!\n", p);
91 print_running_stat(0,0,0,max_mem_used);
92 print_running_stat(0,0,0,max_mem_used);
92 } else {
93 } else {
93 if (!WIFEXITED(stat))
94 if (!WIFEXITED(stat))
94 fprintf(stderr,"wait4: unknown status\n");
95 fprintf(stderr,"wait4: unknown status\n");
95 struct timeval total;
96 struct timeval total;
96 int wall;
97 int wall;
97 wall = time(NULL) - start_time;
98 wall = time(NULL) - start_time;
98 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
99 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
99
100
100 print_running_stat((double)wall,
101 print_running_stat((double)wall,
101 (double) rus.ru_utime.tv_sec +
102 (double) rus.ru_utime.tv_sec +
102 ((double) rus.ru_utime.tv_usec/1000000.0),
103 ((double) rus.ru_utime.tv_usec/1000000.0),
103 (double) rus.ru_stime.tv_sec +
104 (double) rus.ru_stime.tv_sec +
104 ((double) rus.ru_stime.tv_usec/1000000.0),
105 ((double) rus.ru_stime.tv_usec/1000000.0),
105 max_mem_used);
106 max_mem_used);
106 }
107 }
107 exit(1);
108 exit(1);
108 }
109 }
109
110
110 static void NONRET __attribute__((format(printf,1,2)))
111 static void NONRET __attribute__((format(printf,1,2)))
111 die(char *msg, ...)
112 die(char *msg, ...)
112 {
113 {
113 va_list args;
114 va_list args;
114 va_start(args, msg);
115 va_start(args, msg);
115 vfprintf(stderr, msg, args);
116 vfprintf(stderr, msg, args);
116 fputc('\n', stderr);
117 fputc('\n', stderr);
117 box_exit();
118 box_exit();
118 }
119 }
119
120
120 static void __attribute__((format(printf,1,2)))
121 static void __attribute__((format(printf,1,2)))
121 log(char *msg, ...)
122 log(char *msg, ...)
122 {
123 {
123 va_list args;
124 va_list args;
124 va_start(args, msg);
125 va_start(args, msg);
125 if (verbose)
126 if (verbose)
126 {
127 {
127 vfprintf(stderr, msg, args);
128 vfprintf(stderr, msg, args);
128 fflush(stderr);
129 fflush(stderr);
129 }
130 }
130 va_end(args);
131 va_end(args);
131 }
132 }
132
133
133 static void
134 static void
134 valid_filename(unsigned long addr)
135 valid_filename(unsigned long addr)
135 {
136 {
136 char namebuf[4096], *p, *end;
137 char namebuf[4096], *p, *end;
137 static int mem_fd;
138 static int mem_fd;
138
139
139 if (!file_access)
140 if (!file_access)
140 die("File access forbidden.");
141 die("File access forbidden.");
141 if (file_access >= 9)
142 if (file_access >= 9)
142 return;
143 return;
143
144
144 if (!mem_fd)
145 if (!mem_fd)
145 {
146 {
146 sprintf(namebuf, "/proc/%d/mem", (int) box_pid);
147 sprintf(namebuf, "/proc/%d/mem", (int) box_pid);
147 mem_fd = open(namebuf, O_RDONLY);
148 mem_fd = open(namebuf, O_RDONLY);
148 if (mem_fd < 0)
149 if (mem_fd < 0)
149 die("open(%s): %m", namebuf);
150 die("open(%s): %m", namebuf);
150 }
151 }
151 p = end = namebuf;
152 p = end = namebuf;
152 do
153 do
153 {
154 {
154 if (p >= end)
155 if (p >= end)
155 {
156 {
156 int remains = PAGE_SIZE - (addr & (PAGE_SIZE-1));
157 int remains = PAGE_SIZE - (addr & (PAGE_SIZE-1));
157 int l = namebuf + sizeof(namebuf) - end;
158 int l = namebuf + sizeof(namebuf) - end;
158 if (l > remains)
159 if (l > remains)
159 l = remains;
160 l = remains;
160 if (!l)
161 if (!l)
161 die("Access to file with name too long.");
162 die("Access to file with name too long.");
162 if (long_seek(mem_fd, addr, SEEK_SET) < 0)
163 if (long_seek(mem_fd, addr, SEEK_SET) < 0)
163 die("long_seek(mem): %m");
164 die("long_seek(mem): %m");
164 remains = read(mem_fd, end, l);
165 remains = read(mem_fd, end, l);
165 if (remains < 0)
166 if (remains < 0)
166 die("read(mem): %m");
167 die("read(mem): %m");
167 if (!remains)
168 if (!remains)
168 die("Access to file with name out of memory.");
169 die("Access to file with name out of memory.");
169 end += l;
170 end += l;
170 addr += l;
171 addr += l;
171 }
172 }
172 }
173 }
173 while (*p++);
174 while (*p++);
174
175
175 log("[%s] ", namebuf);
176 log("[%s] ", namebuf);
176 if (file_access >= 3)
177 if (file_access >= 3)
177 return;
178 return;
178 if (!strchr(namebuf, '/') && strcmp(namebuf, ".."))
179 if (!strchr(namebuf, '/') && strcmp(namebuf, ".."))
179 return;
180 return;
180 if (file_access >= 2)
181 if (file_access >= 2)
181 {
182 {
182 if ((!strncmp(namebuf, "/etc/", 5) ||
183 if ((!strncmp(namebuf, "/etc/", 5) ||
183 !strncmp(namebuf, "/lib/", 5) ||
184 !strncmp(namebuf, "/lib/", 5) ||
184 !strncmp(namebuf, "/usr/lib/", 9))
185 !strncmp(namebuf, "/usr/lib/", 9))
185 && !strstr(namebuf, ".."))
186 && !strstr(namebuf, ".."))
186 return;
187 return;
187 if (!strcmp(namebuf, "/dev/null") ||
188 if (!strcmp(namebuf, "/dev/null") ||
188 !strcmp(namebuf, "/dev/zero") ||
189 !strcmp(namebuf, "/dev/zero") ||
189 !strcmp(namebuf, "/proc/meminfo") ||
190 !strcmp(namebuf, "/proc/meminfo") ||
190 !strcmp(namebuf, "/proc/self/stat") ||
191 !strcmp(namebuf, "/proc/self/stat") ||
191 !strncmp(namebuf, "/usr/share/zoneinfo/", 20))
192 !strncmp(namebuf, "/usr/share/zoneinfo/", 20))
192 return;
193 return;
193 }
194 }
194 die("Forbidden access to file `%s'.", namebuf);
195 die("Forbidden access to file `%s'.", namebuf);
195 }
196 }
196
197
197 static int
198 static int
198 valid_syscall(struct user *u)
199 valid_syscall(struct user *u)
199 {
200 {
200 switch (u->regs.orig_eax)
201 switch (u->regs.orig_eax)
201 {
202 {
202 case __NR_execve:
203 case __NR_execve:
203 {
204 {
204 static int exec_counter;
205 static int exec_counter;
205 return !exec_counter++;
206 return !exec_counter++;
206 }
207 }
207 case __NR_open:
208 case __NR_open:
208 case __NR_creat:
209 case __NR_creat:
209 case __NR_unlink:
210 case __NR_unlink:
210 case __NR_oldstat:
211 case __NR_oldstat:
211 case __NR_access:
212 case __NR_access:
212 case __NR_oldlstat:
213 case __NR_oldlstat:
213 case __NR_truncate:
214 case __NR_truncate:
214 case __NR_stat:
215 case __NR_stat:
215 case __NR_lstat:
216 case __NR_lstat:
216 case __NR_truncate64:
217 case __NR_truncate64:
217 case __NR_stat64:
218 case __NR_stat64:
218 case __NR_lstat64:
219 case __NR_lstat64:
219 valid_filename(u->regs.ebx);
220 valid_filename(u->regs.ebx);
220 return 1;
221 return 1;
221 case __NR_exit:
222 case __NR_exit:
222 case __NR_read:
223 case __NR_read:
223 case __NR_write:
224 case __NR_write:
224 case __NR_close:
225 case __NR_close:
225 case __NR_lseek:
226 case __NR_lseek:
226 case __NR_getpid:
227 case __NR_getpid:
227 case __NR_getuid:
228 case __NR_getuid:
228 case __NR_oldfstat:
229 case __NR_oldfstat:
229 case __NR_dup:
230 case __NR_dup:
230 case __NR_brk:
231 case __NR_brk:
231 case __NR_getgid:
232 case __NR_getgid:
232 case __NR_geteuid:
233 case __NR_geteuid:
233 case __NR_getegid:
234 case __NR_getegid:
234 case __NR_dup2:
235 case __NR_dup2:
235 case __NR_ftruncate:
236 case __NR_ftruncate:
236 case __NR_fstat:
237 case __NR_fstat:
237 case __NR_personality:
238 case __NR_personality:
238 case __NR__llseek:
239 case __NR__llseek:
239 case __NR_readv:
240 case __NR_readv:
240 case __NR_writev:
241 case __NR_writev:
241 case __NR_getresuid:
242 case __NR_getresuid:
242 #ifdef __NR_pread64
243 #ifdef __NR_pread64
243 case __NR_pread64:
244 case __NR_pread64:
244 case __NR_pwrite64:
245 case __NR_pwrite64:
245 #else
246 #else
246 case __NR_pread:
247 case __NR_pread:
247 case __NR_pwrite:
248 case __NR_pwrite:
248 #endif
249 #endif
249 case __NR_ftruncate64:
250 case __NR_ftruncate64:
250 case __NR_fstat64:
251 case __NR_fstat64:
251 case __NR_fcntl:
252 case __NR_fcntl:
252 case __NR_fcntl64:
253 case __NR_fcntl64:
253 case __NR_mmap:
254 case __NR_mmap:
254 case __NR_munmap:
255 case __NR_munmap:
255 case __NR_ioctl:
256 case __NR_ioctl:
256 case __NR_uname:
257 case __NR_uname:
257 case 252:
258 case 252:
258 case 243:
259 case 243:
259 return 1;
260 return 1;
260 // case __NR_time:
261 // case __NR_time:
261 case __NR_alarm:
262 case __NR_alarm:
262 // case __NR_pause:
263 // case __NR_pause:
263 case __NR_signal:
264 case __NR_signal:
264 case __NR_fchmod:
265 case __NR_fchmod:
265 case __NR_sigaction:
266 case __NR_sigaction:
266 case __NR_sgetmask:
267 case __NR_sgetmask:
267 case __NR_ssetmask:
268 case __NR_ssetmask:
268 case __NR_sigsuspend:
269 case __NR_sigsuspend:
269 case __NR_sigpending:
270 case __NR_sigpending:
270 case __NR_getrlimit:
271 case __NR_getrlimit:
271 case __NR_getrusage:
272 case __NR_getrusage:
272 case __NR_gettimeofday:
273 case __NR_gettimeofday:
273 case __NR_select:
274 case __NR_select:
274 case __NR_readdir:
275 case __NR_readdir:
275 case __NR_setitimer:
276 case __NR_setitimer:
276 case __NR_getitimer:
277 case __NR_getitimer:
277 case __NR_sigreturn:
278 case __NR_sigreturn:
278 case __NR_mprotect:
279 case __NR_mprotect:
279 case __NR_sigprocmask:
280 case __NR_sigprocmask:
280 case __NR_getdents:
281 case __NR_getdents:
281 case __NR_getdents64:
282 case __NR_getdents64:
282 case __NR__newselect:
283 case __NR__newselect:
283 case __NR_fdatasync:
284 case __NR_fdatasync:
284 case __NR_mremap:
285 case __NR_mremap:
285 case __NR_poll:
286 case __NR_poll:
286 case __NR_getcwd:
287 case __NR_getcwd:
287 case __NR_nanosleep:
288 case __NR_nanosleep:
288 case __NR_rt_sigreturn:
289 case __NR_rt_sigreturn:
289 case __NR_rt_sigaction:
290 case __NR_rt_sigaction:
290 case __NR_rt_sigprocmask:
291 case __NR_rt_sigprocmask:
291 case __NR_rt_sigpending:
292 case __NR_rt_sigpending:
292 case __NR_rt_sigtimedwait:
293 case __NR_rt_sigtimedwait:
293 case __NR_rt_sigqueueinfo:
294 case __NR_rt_sigqueueinfo:
294 case __NR_rt_sigsuspend:
295 case __NR_rt_sigsuspend:
295 case __NR_mmap2:
296 case __NR_mmap2:
296 case __NR__sysctl:
297 case __NR__sysctl:
297 return (filter_syscalls == 1);
298 return (filter_syscalls == 1);
298 case __NR_times:
299 case __NR_times:
299 return allow_times;
300 return allow_times;
300 case __NR_kill:
301 case __NR_kill:
301 if (u->regs.ebx == box_pid)
302 if (u->regs.ebx == box_pid)
302 die("Commited suicide by signal %d.", (int)u->regs.ecx);
303 die("Commited suicide by signal %d.", (int)u->regs.ecx);
303 return 0;
304 return 0;
304 default:
305 default:
305 return 0;
306 return 0;
306 }
307 }
307 }
308 }
308
309
309 static void
310 static void
310 signal_alarm(int unused UNUSED)
311 signal_alarm(int unused UNUSED)
311 {
312 {
312 /* Time limit checks are synchronous, so we only schedule them there. */
313 /* Time limit checks are synchronous, so we only schedule them there. */
313 timer_tick = 1;
314 timer_tick = 1;
314
315
315 //NOTE: do not use alarm, changed to setitimer for precision
316 //NOTE: do not use alarm, changed to setitimer for precision
316 // alarm(1);
317 // alarm(1);
317 }
318 }
318
319
319 static void
320 static void
320 signal_int(int unused UNUSED)
321 signal_int(int unused UNUSED)
321 {
322 {
322 /* Interrupts are fatal, so no synchronization requirements. */
323 /* Interrupts are fatal, so no synchronization requirements. */
323 die("Interrupted.");
324 die("Interrupted.");
324 }
325 }
325
326
326 static void
327 static void
327 check_timeout(void)
328 check_timeout(void)
328 {
329 {
329 int sec;
330 int sec;
330
331
331 if (use_wall_clock)
332 if (use_wall_clock)
332 sec = time(NULL) - start_time;
333 sec = time(NULL) - start_time;
333 else
334 else
334 {
335 {
335 char buf[4096], *x;
336 char buf[4096], *x;
336 int c, utime, stime;
337 int c, utime, stime;
337 static int proc_status_fd;
338 static int proc_status_fd;
338 if (!proc_status_fd)
339 if (!proc_status_fd)
339 {
340 {
340 sprintf(buf, "/proc/%d/stat", (int) box_pid);
341 sprintf(buf, "/proc/%d/stat", (int) box_pid);
341 proc_status_fd = open(buf, O_RDONLY);
342 proc_status_fd = open(buf, O_RDONLY);
342 if (proc_status_fd < 0)
343 if (proc_status_fd < 0)
343 die("open(%s): %m", buf);
344 die("open(%s): %m", buf);
344 }
345 }
345 lseek(proc_status_fd, 0, SEEK_SET);
346 lseek(proc_status_fd, 0, SEEK_SET);
346 if ((c = read(proc_status_fd, buf, sizeof(buf)-1)) < 0)
347 if ((c = read(proc_status_fd, buf, sizeof(buf)-1)) < 0)
347 die("read on /proc/$pid/stat: %m");
348 die("read on /proc/$pid/stat: %m");
348 if (c >= (int) sizeof(buf) - 1)
349 if (c >= (int) sizeof(buf) - 1)
349 die("/proc/$pid/stat too long");
350 die("/proc/$pid/stat too long");
350 buf[c] = 0;
351 buf[c] = 0;
351 x = buf;
352 x = buf;
352 while (*x && *x != ' ')
353 while (*x && *x != ' ')
353 x++;
354 x++;
354 while (*x == ' ')
355 while (*x == ' ')
355 x++;
356 x++;
356 if (*x++ != '(')
357 if (*x++ != '(')
357 die("proc syntax error 1");
358 die("proc syntax error 1");
358 while (*x && (*x != ')' || x[1] != ' '))
359 while (*x && (*x != ')' || x[1] != ' '))
359 x++;
360 x++;
360 while (*x == ')' || *x == ' ')
361 while (*x == ')' || *x == ' ')
361 x++;
362 x++;
362 if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
363 if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
363 die("proc syntax error 2");
364 die("proc syntax error 2");
364 //printf("%s - %d\n",x,ticks_per_sec);
365 //printf("%s - %d\n",x,ticks_per_sec);
365 sec = (utime + stime + ticks_per_sec-1)/ticks_per_sec;
366 sec = (utime + stime + ticks_per_sec-1)/ticks_per_sec;
366 }
367 }
367 if (verbose > 1)
368 if (verbose > 1)
368 fprintf(stderr, "[timecheck: %d seconds]\n", sec);
369 fprintf(stderr, "[timecheck: %d seconds]\n", sec);
369 if (sec > timeout) {
370 if (sec > timeout) {
370 die("Time limit exceeded.");
371 die("Time limit exceeded.");
371 }
372 }
372 }
373 }
373
374
374 static void
375 static void
375 check_memory_usage()
376 check_memory_usage()
376 {
377 {
377 char proc_fname[100];
378 char proc_fname[100];
378 sprintf(proc_fname,"/proc/%d/statm",box_pid);
379 sprintf(proc_fname,"/proc/%d/statm",box_pid);
379 //printf("proc fname: %s\n",proc_fname);
380 //printf("proc fname: %s\n",proc_fname);
380 FILE *fp = fopen(proc_fname,"r");
381 FILE *fp = fopen(proc_fname,"r");
381 if(fp!=NULL) {
382 if(fp!=NULL) {
382 char line[1000];
383 char line[1000];
383 fgets(line,999,fp);
384 fgets(line,999,fp);
384 //printf("%s\n",line);
385 //printf("%s\n",line);
385 int m;
386 int m;
386
387
387 - if(sscanf(line,"%d",&m)==1)
388 + if(sscanf(line,"%d",&m)==1) {
389 + m = (m*page_size+1023)/1024;
388 if(m>max_mem_used)
390 if(m>max_mem_used)
389 max_mem_used = m;
391 max_mem_used = m;
392 + }
390
393
391 fclose(fp);
394 fclose(fp);
392 }
395 }
393 }
396 }
394
397
395 static void
398 static void
396 boxkeeper(void)
399 boxkeeper(void)
397 {
400 {
398 int syscall_count = 0;
401 int syscall_count = 0;
399 struct sigaction sa;
402 struct sigaction sa;
400
403
401 is_ptraced = 1;
404 is_ptraced = 1;
402 bzero(&sa, sizeof(sa));
405 bzero(&sa, sizeof(sa));
403 sa.sa_handler = signal_int;
406 sa.sa_handler = signal_int;
404 sigaction(SIGINT, &sa, NULL);
407 sigaction(SIGINT, &sa, NULL);
405 start_time = time(NULL);
408 start_time = time(NULL);
406 ticks_per_sec = sysconf(_SC_CLK_TCK);
409 ticks_per_sec = sysconf(_SC_CLK_TCK);
410 + page_size = getpagesize();
407 if (ticks_per_sec <= 0)
411 if (ticks_per_sec <= 0)
408 die("Invalid ticks_per_sec!");
412 die("Invalid ticks_per_sec!");
409
413
410 check_memory_usage();
414 check_memory_usage();
411
415
412 sa.sa_handler = signal_alarm;
416 sa.sa_handler = signal_alarm;
413 sigaction(SIGALRM, &sa, NULL);
417 sigaction(SIGALRM, &sa, NULL);
414 //alarm(1);
418 //alarm(1);
415
419
416 struct itimerval val;
420 struct itimerval val;
417 val.it_interval.tv_sec = 0;
421 val.it_interval.tv_sec = 0;
418 val.it_interval.tv_usec = 50000;
422 val.it_interval.tv_usec = 50000;
419 val.it_value.tv_sec = 0;
423 val.it_value.tv_sec = 0;
420 val.it_value.tv_usec = 50000;
424 val.it_value.tv_usec = 50000;
421 setitimer(ITIMER_REAL,&val,NULL);
425 setitimer(ITIMER_REAL,&val,NULL);
422
426
423 /*
427 /*
424 --- add alarm handler no matter what..
428 --- add alarm handler no matter what..
425 if (timeout)
429 if (timeout)
426 {
430 {
427 sa.sa_handler = signal_alarm;
431 sa.sa_handler = signal_alarm;
428 sigaction(SIGALRM, &sa, NULL);
432 sigaction(SIGALRM, &sa, NULL);
429 alarm(1);
433 alarm(1);
430 }
434 }
431 */
435 */
432
436
433 for(;;)
437 for(;;)
434 {
438 {
435 struct rusage rus;
439 struct rusage rus;
436 int stat;
440 int stat;
437 pid_t p;
441 pid_t p;
438
442
439 if (timer_tick)
443 if (timer_tick)
440 {
444 {
441 check_timeout();
445 check_timeout();
442 check_memory_usage();
446 check_memory_usage();
443 timer_tick = 0;
447 timer_tick = 0;
444 }
448 }
445 p = wait4(box_pid, &stat, WUNTRACED, &rus);
449 p = wait4(box_pid, &stat, WUNTRACED, &rus);
446
450
447 if (p < 0)
451 if (p < 0)
448 {
452 {
449 if (errno == EINTR)
453 if (errno == EINTR)
450 continue;
454 continue;
451 die("wait4: %m");
455 die("wait4: %m");
452 }
456 }
453 if (p != box_pid)
457 if (p != box_pid)
454 die("wait4: unknown pid %d exited!", p);
458 die("wait4: unknown pid %d exited!", p);
455 if (WIFEXITED(stat))
459 if (WIFEXITED(stat))
456 {
460 {
457 struct timeval total;
461 struct timeval total;
458 int wall;
462 int wall;
459 wall = time(NULL) - start_time;
463 wall = time(NULL) - start_time;
460 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
464 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
461
465
462 box_pid = 0;
466 box_pid = 0;
463 if (WEXITSTATUS(stat))
467 if (WEXITSTATUS(stat))
464 fprintf(stderr,"Exited with error status %d.\n", WEXITSTATUS(stat));
468 fprintf(stderr,"Exited with error status %d.\n", WEXITSTATUS(stat));
465 else if ((use_wall_clock ? wall : total.tv_sec) > timeout)
469 else if ((use_wall_clock ? wall : total.tv_sec) > timeout)
466 fprintf(stderr,"Time limit exceeded.\n");
470 fprintf(stderr,"Time limit exceeded.\n");
467 else
471 else
468 // report OK and statistics
472 // report OK and statistics
469 fprintf(stderr,"OK\n");
473 fprintf(stderr,"OK\n");
470
474
471 print_running_stat((double) wall,
475 print_running_stat((double) wall,
472 (double) rus.ru_utime.tv_sec +
476 (double) rus.ru_utime.tv_sec +
473 ((double) rus.ru_utime.tv_usec/1000000.0),
477 ((double) rus.ru_utime.tv_usec/1000000.0),
474 (double) rus.ru_stime.tv_sec +
478 (double) rus.ru_stime.tv_sec +
475 ((double) rus.ru_stime.tv_usec/1000000.0),
479 ((double) rus.ru_stime.tv_usec/1000000.0),
476 max_mem_used);
480 max_mem_used);
477 /*
481 /*
478 (%.4lf sec real (%d), %d sec wall, %d syscalls, %d kb)\n",
482 (%.4lf sec real (%d), %d sec wall, %d syscalls, %d kb)\n",
479 (double) total.tv_sec + ((double)total.tv_usec / 1000000.0),
483 (double) total.tv_sec + ((double)total.tv_usec / 1000000.0),
480 (int) total.tv_usec,
484 (int) total.tv_usec,
481 wall,
485 wall,
482 syscall_count,
486 syscall_count,
483 max_mem_used);
487 max_mem_used);
484 */
488 */
485 exit(0);
489 exit(0);
486 }
490 }
487 if (WIFSIGNALED(stat))
491 if (WIFSIGNALED(stat))
488 {
492 {
489 box_pid = 0;
493 box_pid = 0;
490 fprintf(stderr,"Caught fatal signal %d.\n", WTERMSIG(stat));
494 fprintf(stderr,"Caught fatal signal %d.\n", WTERMSIG(stat));
491
495
492 struct timeval total;
496 struct timeval total;
493 int wall;
497 int wall;
494 wall = time(NULL) - start_time;
498 wall = time(NULL) - start_time;
495 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
499 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
496 print_running_stat((double) wall,
500 print_running_stat((double) wall,
497 (double) rus.ru_utime.tv_sec +
501 (double) rus.ru_utime.tv_sec +
498 ((double) rus.ru_utime.tv_usec/1000000.0),
502 ((double) rus.ru_utime.tv_usec/1000000.0),
499 (double) rus.ru_stime.tv_sec +
503 (double) rus.ru_stime.tv_sec +
500 ((double) rus.ru_stime.tv_usec/1000000.0),
504 ((double) rus.ru_stime.tv_usec/1000000.0),
501 max_mem_used);
505 max_mem_used);
502 exit(0);
506 exit(0);
503 }
507 }
504 if (WIFSTOPPED(stat))
508 if (WIFSTOPPED(stat))
505 {
509 {
506 int sig = WSTOPSIG(stat);
510 int sig = WSTOPSIG(stat);
507 if (sig == SIGTRAP)
511 if (sig == SIGTRAP)
508 {
512 {
509 struct user u;
513 struct user u;
510 static int stop_count = -1;
514 static int stop_count = -1;
511 if (ptrace(PTRACE_GETREGS, box_pid, NULL, &u) < 0)
515 if (ptrace(PTRACE_GETREGS, box_pid, NULL, &u) < 0)
512 die("ptrace(PTRACE_GETREGS): %m");
516 die("ptrace(PTRACE_GETREGS): %m");
513 stop_count++;
517 stop_count++;
514 if (!stop_count) /* Traceme request */
518 if (!stop_count) /* Traceme request */
515 log(">> Traceme request caught\n");
519 log(">> Traceme request caught\n");
516 else if (stop_count & 1) /* Syscall entry */
520 else if (stop_count & 1) /* Syscall entry */
517 {
521 {
518 log(">> Syscall %3ld (%08lx,%08lx,%08lx) ", u.regs.orig_eax, u.regs.ebx, u.regs.ecx, u.regs.edx);
522 log(">> Syscall %3ld (%08lx,%08lx,%08lx) ", u.regs.orig_eax, u.regs.ebx, u.regs.ecx, u.regs.edx);
519 syscall_count++;
523 syscall_count++;
520 if (!valid_syscall(&u))
524 if (!valid_syscall(&u))
521 {
525 {
522 /*
526 /*
523 * Unfortunately, PTRACE_KILL kills _after_ the syscall completes,
527 * Unfortunately, PTRACE_KILL kills _after_ the syscall completes,
524 * so we have to change it to something harmless (e.g., an undefined
528 * so we have to change it to something harmless (e.g., an undefined
525 * syscall) and make the program continue.
529 * syscall) and make the program continue.
526 */
530 */
527 unsigned int sys = u.regs.orig_eax;
531 unsigned int sys = u.regs.orig_eax;
528 u.regs.orig_eax = 0xffffffff;
532 u.regs.orig_eax = 0xffffffff;
529 if (ptrace(PTRACE_SETREGS, box_pid, NULL, &u) < 0)
533 if (ptrace(PTRACE_SETREGS, box_pid, NULL, &u) < 0)
530 die("ptrace(PTRACE_SETREGS): %m");
534 die("ptrace(PTRACE_SETREGS): %m");
531 die("Forbidden syscall %d.", sys);
535 die("Forbidden syscall %d.", sys);
532 }
536 }
533 }
537 }
534 else /* Syscall return */
538 else /* Syscall return */
535 log("= %ld\n", u.regs.eax);
539 log("= %ld\n", u.regs.eax);
536 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
540 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
537 }
541 }
538 else if (sig != SIGSTOP && sig != SIGXCPU && sig != SIGXFSZ)
542 else if (sig != SIGSTOP && sig != SIGXCPU && sig != SIGXFSZ)
539 {
543 {
540 log(">> Signal %d\n", sig);
544 log(">> Signal %d\n", sig);
541 ptrace(PTRACE_SYSCALL, box_pid, 0, sig);
545 ptrace(PTRACE_SYSCALL, box_pid, 0, sig);
542 }
546 }
543 else
547 else
544 die("Received signal %d.", sig);
548 die("Received signal %d.", sig);
545 }
549 }
546 else
550 else
547 die("wait4: unknown status %x, giving up!", stat);
551 die("wait4: unknown status %x, giving up!", stat);
548 }
552 }
549 }
553 }
550
554
551 static void
555 static void
552 box_inside(int argc, char **argv)
556 box_inside(int argc, char **argv)
553 {
557 {
554 struct rlimit rl;
558 struct rlimit rl;
555 char *args[argc+1];
559 char *args[argc+1];
556 char *env[1] = { NULL };
560 char *env[1] = { NULL };
557
561
558 memcpy(args, argv, argc * sizeof(char *));
562 memcpy(args, argv, argc * sizeof(char *));
559 args[argc] = NULL;
563 args[argc] = NULL;
560 if (set_cwd && chdir(set_cwd))
564 if (set_cwd && chdir(set_cwd))
561 die("chdir: %m");
565 die("chdir: %m");
562 if (redir_stdin)
566 if (redir_stdin)
563 {
567 {
564 close(0);
568 close(0);
565 if (open(redir_stdin, O_RDONLY) != 0)
569 if (open(redir_stdin, O_RDONLY) != 0)
566 die("open(\"%s\"): %m", redir_stdin);
570 die("open(\"%s\"): %m", redir_stdin);
567 }
571 }
568 if (redir_stdout)
572 if (redir_stdout)
569 {
573 {
570 close(1);
574 close(1);
571 if (open(redir_stdout, O_WRONLY | O_CREAT | O_TRUNC, 0666) != 1)
575 if (open(redir_stdout, O_WRONLY | O_CREAT | O_TRUNC, 0666) != 1)
572 die("open(\"%s\"): %m", redir_stdout);
576 die("open(\"%s\"): %m", redir_stdout);
573 }
577 }
574 dup2(1, 2);
578 dup2(1, 2);
575 setpgrp();
579 setpgrp();
576 if (memory_limit)
580 if (memory_limit)
577 {
581 {
578 rl.rlim_cur = rl.rlim_max = memory_limit * 1024;
582 rl.rlim_cur = rl.rlim_max = memory_limit * 1024;
579 if (setrlimit(RLIMIT_AS, &rl) < 0)
583 if (setrlimit(RLIMIT_AS, &rl) < 0)
580 die("setrlimit: %m");
584 die("setrlimit: %m");
581 }
585 }
582 rl.rlim_cur = rl.rlim_max = 64;
586 rl.rlim_cur = rl.rlim_max = 64;
583 if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
587 if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
584 die("setrlimit: %m");
588 die("setrlimit: %m");
585 if (filter_syscalls && ptrace(PTRACE_TRACEME) < 0)
589 if (filter_syscalls && ptrace(PTRACE_TRACEME) < 0)
586 die("ptrace(PTRACE_TRACEME): %m");
590 die("ptrace(PTRACE_TRACEME): %m");
587 execve(args[0], args, (pass_environ ? environ : env));
591 execve(args[0], args, (pass_environ ? environ : env));
588 die("execve(\"%s\"): %m", args[0]);
592 die("execve(\"%s\"): %m", args[0]);
589 }
593 }
590
594
591 static void
595 static void
592 usage(void)
596 usage(void)
593 {
597 {
594 fprintf(stderr, "Invalid arguments!\n");
598 fprintf(stderr, "Invalid arguments!\n");
595 printf("\
599 printf("\
596 Usage: box [<options>] -- <command> <arguments>\n\
600 Usage: box [<options>] -- <command> <arguments>\n\
597 \n\
601 \n\
598 Options:\n\
602 Options:\n\
599 -a <level>\tSet file access level (0=none, 1=cwd, 2=/etc,/lib,..., 3=whole fs, 9=no checks; needs -f)\n\
603 -a <level>\tSet file access level (0=none, 1=cwd, 2=/etc,/lib,..., 3=whole fs, 9=no checks; needs -f)\n\
600 -c <dir>\tChange directory to <dir> first\n\
604 -c <dir>\tChange directory to <dir> first\n\
601 -e\t\tPass full environment of parent process\n\
605 -e\t\tPass full environment of parent process\n\
602 -f\t\tFilter system calls (-ff=very restricted)\n\
606 -f\t\tFilter system calls (-ff=very restricted)\n\
603 -i <file>\tRedirect stdin from <file>\n\
607 -i <file>\tRedirect stdin from <file>\n\
604 -m <size>\tLimit address space to <size> KB\n\
608 -m <size>\tLimit address space to <size> KB\n\
605 -o <file>\tRedirect stdout to <file>\n\
609 -o <file>\tRedirect stdout to <file>\n\
606 -t <time>\tStop after <time> seconds\n\
610 -t <time>\tStop after <time> seconds\n\
607 -T\t\tAllow syscalls for measuring run time\n\
611 -T\t\tAllow syscalls for measuring run time\n\
608 -v\t\tBe verbose\n\
612 -v\t\tBe verbose\n\
609 -w\t\tMeasure wall clock time instead of run time\n\
613 -w\t\tMeasure wall clock time instead of run time\n\
610 ");
614 ");
611 exit(1);
615 exit(1);
612 }
616 }
613
617
614 int
618 int
615 main(int argc, char **argv)
619 main(int argc, char **argv)
616 {
620 {
617 int c;
621 int c;
618 uid_t uid;
622 uid_t uid;
619
623
620 while ((c = getopt(argc, argv, "a:c:efi:m:o:t:Tvw")) >= 0)
624 while ((c = getopt(argc, argv, "a:c:efi:m:o:t:Tvw")) >= 0)
621 switch (c)
625 switch (c)
622 {
626 {
623 case 'a':
627 case 'a':
624 file_access = atol(optarg);
628 file_access = atol(optarg);
625 break;
629 break;
626 case 'c':
630 case 'c':
627 set_cwd = optarg;
631 set_cwd = optarg;
628 break;
632 break;
629 case 'e':
633 case 'e':
630 pass_environ = 1;
634 pass_environ = 1;
631 break;
635 break;
632 case 'f':
636 case 'f':
633 filter_syscalls++;
637 filter_syscalls++;
634 break;
638 break;
635 case 'i':
639 case 'i':
636 redir_stdin = optarg;
640 redir_stdin = optarg;
637 break;
641 break;
638 case 'm':
642 case 'm':
639 memory_limit = atol(optarg);
643 memory_limit = atol(optarg);
640 break;
644 break;
641 case 'o':
645 case 'o':
642 redir_stdout = optarg;
646 redir_stdout = optarg;
643 break;
647 break;
644 case 't':
648 case 't':
645 timeout = atol(optarg);
649 timeout = atol(optarg);
646 break;
650 break;
647 case 'T':
651 case 'T':
648 allow_times++;
652 allow_times++;
649 break;
653 break;
650 case 'v':
654 case 'v':
651 verbose++;
655 verbose++;
652 break;
656 break;
653 case 'w':
657 case 'w':
654 use_wall_clock = 1;
658 use_wall_clock = 1;
655 break;
659 break;
656 default:
660 default:
657 usage();
661 usage();
658 }
662 }
659 if (optind >= argc)
663 if (optind >= argc)
660 usage();
664 usage();
661
665
662 uid = geteuid();
666 uid = geteuid();
663 if (setreuid(uid, uid) < 0)
667 if (setreuid(uid, uid) < 0)
664 die("setreuid: %m");
668 die("setreuid: %m");
665 box_pid = fork();
669 box_pid = fork();
666 if (box_pid < 0)
670 if (box_pid < 0)
667 die("fork: %m");
671 die("fork: %m");
668 if (!box_pid)
672 if (!box_pid)
669 box_inside(argc-optind, argv+optind);
673 box_inside(argc-optind, argv+optind);
670 else
674 else
671 boxkeeper();
675 boxkeeper();
672 die("Internal error: fell over edge of the world");
676 die("Internal error: fell over edge of the world");
673 }
677 }
You need to be logged in to leave comments. Login now