Description:
change memory resolution in report to kbytes
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r164:447fdbbeac2c - - 3 files changed: 4 inserted, 4 deleted

@@ -1,254 +1,254
1 #
1 #
2 # This part contains various test_request helpers for interfacing
2 # This part contains various test_request helpers for interfacing
3 # with Grader::Engine. There are TestRequestRoomMaker and
3 # with Grader::Engine. There are TestRequestRoomMaker and
4 # TestRequestReporter.
4 # TestRequestReporter.
5
5
6 module Grader
6 module Grader
7
7
8 def self.link_or_copy(src, des)
8 def self.link_or_copy(src, des)
9 begin
9 begin
10 FileUtils.ln_s(src, des)
10 FileUtils.ln_s(src, des)
11 rescue NotImplementedError
11 rescue NotImplementedError
12 FileUtils.cp(src,des)
12 FileUtils.cp(src,des)
13 end
13 end
14 end
14 end
15
15
16 def self.call_and_log(error_message)
16 def self.call_and_log(error_message)
17 begin
17 begin
18 yield
18 yield
19 rescue
19 rescue
20 msg = "ERROR: #{error_message}"
20 msg = "ERROR: #{error_message}"
21 raise msg
21 raise msg
22 end
22 end
23 end
23 end
24
24
25 #
25 #
26 # A TestRequestRoomMaker is a helper object for Engine
26 # A TestRequestRoomMaker is a helper object for Engine
27 # - finds grading room: in user_result_dir/(user)/test_request/ ...
27 # - finds grading room: in user_result_dir/(user)/test_request/ ...
28 # - prepare problem configuration for grading --- basically it copy
28 # - prepare problem configuration for grading --- basically it copy
29 # all config files, and copy user's input into the testcase
29 # all config files, and copy user's input into the testcase
30 # directory. First, it finds the template from problem template
30 # directory. First, it finds the template from problem template
31 # directory; if it can't find a template, it'll use the template
31 # directory; if it can't find a template, it'll use the template
32 # from default template.
32 # from default template.
33 class TestRequestRoomMaker
33 class TestRequestRoomMaker
34 def initialize
34 def initialize
35 @config = Grader::Configuration.get_instance
35 @config = Grader::Configuration.get_instance
36 end
36 end
37
37
38 def produce_grading_room(test_request)
38 def produce_grading_room(test_request)
39 grading_room = grading_room_dir(test_request)
39 grading_room = grading_room_dir(test_request)
40 FileUtils.mkdir_p(grading_room)
40 FileUtils.mkdir_p(grading_room)
41
41
42 #
42 #
43 # Also copy additional submitted file to this directory as well.
43 # Also copy additional submitted file to this directory as well.
44 # The program would see this file only if it is copied
44 # The program would see this file only if it is copied
45 # to the sandbox directory later. The run script should do it.
45 # to the sandbox directory later. The run script should do it.
46 #
46 #
47 if FileTest.exists?("#{test_request.input_file_name}.files")
47 if FileTest.exists?("#{test_request.input_file_name}.files")
48 FileUtils.cp_r("#{test_request.input_file_name}.files/.",
48 FileUtils.cp_r("#{test_request.input_file_name}.files/.",
49 "#{grading_room}")
49 "#{grading_room}")
50 end
50 end
51
51
52 grading_room
52 grading_room
53 end
53 end
54
54
55 def find_problem_home(test_request)
55 def find_problem_home(test_request)
56 problem_name = test_request.problem_name
56 problem_name = test_request.problem_name
57
57
58 template_dir = "#{@config.test_request_problem_templates_dir}/" + problem_name
58 template_dir = "#{@config.test_request_problem_templates_dir}/" + problem_name
59
59
60 raise "Test Request: error template not found" if !File.exists?(template_dir)
60 raise "Test Request: error template not found" if !File.exists?(template_dir)
61
61
62 problem_home = problem_home_dir(test_request)
62 problem_home = problem_home_dir(test_request)
63 FileUtils.mkdir_p(problem_home)
63 FileUtils.mkdir_p(problem_home)
64
64
65 copy_problem_template(template_dir,problem_home)
65 copy_problem_template(template_dir,problem_home)
66 link_input_file(test_request,problem_home)
66 link_input_file(test_request,problem_home)
67
67
68 problem_home
68 problem_home
69 end
69 end
70
70
71 def save_source(test_request,source_name)
71 def save_source(test_request,source_name)
72 dir = self.produce_grading_room(test_request)
72 dir = self.produce_grading_room(test_request)
73 submission = test_request.submission
73 submission = test_request.submission
74 f = File.open("#{dir}/#{source_name}","w")
74 f = File.open("#{dir}/#{source_name}","w")
75 f.write(submission.source)
75 f.write(submission.source)
76 f.close
76 f.close
77 end
77 end
78
78
79 def clean_up(test_request)
79 def clean_up(test_request)
80 problem_home = problem_home_dir(test_request)
80 problem_home = problem_home_dir(test_request)
81 remove_data_files(problem_home)
81 remove_data_files(problem_home)
82 end
82 end
83
83
84 protected
84 protected
85 def grading_room_dir(test_request)
85 def grading_room_dir(test_request)
86 problem_name = test_request.problem_name
86 problem_name = test_request.problem_name
87 user = test_request.user
87 user = test_request.user
88 grading_room = "#{@config.user_result_dir}" +
88 grading_room = "#{@config.user_result_dir}" +
89 "/#{user.login}/test_request" +
89 "/#{user.login}/test_request" +
90 "/#{problem_name}/#{test_request.id}"
90 "/#{problem_name}/#{test_request.id}"
91 grading_room
91 grading_room
92 end
92 end
93
93
94 def problem_home_dir(test_request)
94 def problem_home_dir(test_request)
95 problem_name = test_request.problem_name
95 problem_name = test_request.problem_name
96 user = test_request.user
96 user = test_request.user
97 "#{@config.user_result_dir}" +
97 "#{@config.user_result_dir}" +
98 "/#{user.login}/test_request/#{problem_name}"
98 "/#{user.login}/test_request/#{problem_name}"
99 end
99 end
100
100
101 def copy_problem_template(template_dir,problem_home)
101 def copy_problem_template(template_dir,problem_home)
102 Grader::call_and_log("Test Request: cannot copy problem template") {
102 Grader::call_and_log("Test Request: cannot copy problem template") {
103 FileUtils.cp_r("#{template_dir}/.","#{problem_home}")
103 FileUtils.cp_r("#{template_dir}/.","#{problem_home}")
104 }
104 }
105 end
105 end
106
106
107 def link_input_file(test_request, problem_home)
107 def link_input_file(test_request, problem_home)
108 input_fname = "#{test_request.input_file_name}"
108 input_fname = "#{test_request.input_file_name}"
109 if !File.exists?(input_fname)
109 if !File.exists?(input_fname)
110 raise "Test Request: input file not found."
110 raise "Test Request: input file not found."
111 end
111 end
112
112
113 input_fname_problem_home = "#{problem_home}/test_cases/1/input-1.txt"
113 input_fname_problem_home = "#{problem_home}/test_cases/1/input-1.txt"
114 if File.exists?(input_fname_problem_home)
114 if File.exists?(input_fname_problem_home)
115 FileUtils.rm([input_fname_problem_home], :force => true)
115 FileUtils.rm([input_fname_problem_home], :force => true)
116 end
116 end
117
117
118 Grader::link_or_copy("#{input_fname}", "#{input_fname_problem_home}")
118 Grader::link_or_copy("#{input_fname}", "#{input_fname_problem_home}")
119 end
119 end
120
120
121 def remove_data_files(problem_home)
121 def remove_data_files(problem_home)
122 if File.exists?("#{problem_home}/test_cases/1/input-1.txt")
122 if File.exists?("#{problem_home}/test_cases/1/input-1.txt")
123 Grader::call_and_log("Test Request: cannot remove data files") {
123 Grader::call_and_log("Test Request: cannot remove data files") {
124 FileUtils.rm Dir.glob("#{problem_home}/test_cases/1/*")
124 FileUtils.rm Dir.glob("#{problem_home}/test_cases/1/*")
125 }
125 }
126 end
126 end
127 end
127 end
128
128
129 end
129 end
130
130
131 class TestRequestReporter
131 class TestRequestReporter
132 def initialize
132 def initialize
133 @config = Grader::Configuration.get_instance
133 @config = Grader::Configuration.get_instance
134 end
134 end
135
135
136 def report(test_request,test_result_dir)
136 def report(test_request,test_result_dir)
137 save_result(test_request,read_result(test_result_dir))
137 save_result(test_request,read_result(test_result_dir))
138 end
138 end
139
139
140 def report_error(test_request, msg)
140 def report_error(test_request, msg)
141 save_result(test_request, {:running_stat => {
141 save_result(test_request, {:running_stat => {
142 :msg => "#{msg}",
142 :msg => "#{msg}",
143 :running_time => nil,
143 :running_time => nil,
144 :exit_status => "Some error occured. Program did not run",
144 :exit_status => "Some error occured. Program did not run",
145 :memory_usage => nil
145 :memory_usage => nil
146 }})
146 }})
147 end
147 end
148
148
149 protected
149 protected
150 def read_result(test_result_dir)
150 def read_result(test_result_dir)
151 # TODO:
151 # TODO:
152 cmp_msg_fname = "#{test_result_dir}/compiler_message"
152 cmp_msg_fname = "#{test_result_dir}/compiler_message"
153 cmp_file = File.open(cmp_msg_fname)
153 cmp_file = File.open(cmp_msg_fname)
154 cmp_msg = cmp_file.read
154 cmp_msg = cmp_file.read
155 cmp_file.close
155 cmp_file.close
156
156
157 result_file_name = "#{test_result_dir}/1/result"
157 result_file_name = "#{test_result_dir}/1/result"
158
158
159 if File.exists?(result_file_name)
159 if File.exists?(result_file_name)
160 output_file_name = "#{test_result_dir}/1/output.txt"
160 output_file_name = "#{test_result_dir}/1/output.txt"
161 results = []
161 results = []
162 File.open("#{test_result_dir}/1/result") do |f|
162 File.open("#{test_result_dir}/1/result") do |f|
163 results = f.readlines
163 results = f.readlines
164 end
164 end
165 stat = extract_running_stat(results)
165 stat = extract_running_stat(results)
166
166
167 return {
167 return {
168 :output_file_name => output_file_name,
168 :output_file_name => output_file_name,
169 :running_stat => stat,
169 :running_stat => stat,
170 :comment => "",
170 :comment => "",
171 :cmp_msg => cmp_msg}
171 :cmp_msg => cmp_msg}
172 else
172 else
173 return {
173 return {
174 :running_stat => nil,
174 :running_stat => nil,
175 :comment => "Compilation error",
175 :comment => "Compilation error",
176 :cmp_msg => cmp_msg}
176 :cmp_msg => cmp_msg}
177 end
177 end
178 end
178 end
179
179
180 def extract_running_stat(results)
180 def extract_running_stat(results)
181 running_stat_line = results[-1]
181 running_stat_line = results[-1]
182
182
183 # extract exit status line
183 # extract exit status line
184 run_stat = ""
184 run_stat = ""
185 if !(/[Cc]orrect/.match(results[0]))
185 if !(/[Cc]orrect/.match(results[0]))
186 run_stat = results[0].chomp
186 run_stat = results[0].chomp
187 else
187 else
188 run_stat = 'Program exited normally'
188 run_stat = 'Program exited normally'
189 end
189 end
190
190
191 # extract running time
191 # extract running time
192 if res = /r(.*)u(.*)s/.match(running_stat_line)
192 if res = /r(.*)u(.*)s/.match(running_stat_line)
193 seconds = (res[1].to_f + res[2].to_f)
193 seconds = (res[1].to_f + res[2].to_f)
194 time_stat = "Time used: #{seconds} sec."
194 time_stat = "Time used: #{seconds} sec."
195 else
195 else
196 seconds = nil
196 seconds = nil
197 time_stat = "Time used: n/a sec."
197 time_stat = "Time used: n/a sec."
198 end
198 end
199
199
200 # extract memory usage
200 # extract memory usage
201 - if res = /s(.*)m/.match(running_stat_line)
201 + if res = /s(.*)kbytes/.match(running_stat_line)
202 memory_used = res[1].to_i
202 memory_used = res[1].to_i
203 else
203 else
204 memory_used = -1
204 memory_used = -1
205 end
205 end
206
206
207 return {
207 return {
208 :msg => "#{run_stat}\n#{time_stat}",
208 :msg => "#{run_stat}\n#{time_stat}",
209 :running_time => seconds,
209 :running_time => seconds,
210 :exit_status => run_stat,
210 :exit_status => run_stat,
211 :memory_usage => memory_used
211 :memory_usage => memory_used
212 }
212 }
213 end
213 end
214
214
215 def save_result(test_request,result)
215 def save_result(test_request,result)
216 if result[:output_file_name]!=nil
216 if result[:output_file_name]!=nil
217 test_request.output_file_name = link_output_file(test_request,
217 test_request.output_file_name = link_output_file(test_request,
218 result[:output_file_name])
218 result[:output_file_name])
219 end
219 end
220 test_request.graded_at = Time.now
220 test_request.graded_at = Time.now
221 test_request.compiler_message = (result[:cmp_msg] or '')
221 test_request.compiler_message = (result[:cmp_msg] or '')
222 test_request.grader_comment = (result[:comment] or '')
222 test_request.grader_comment = (result[:comment] or '')
223 if result[:running_stat]!=nil
223 if result[:running_stat]!=nil
224 test_request.running_stat = (result[:running_stat][:msg] or '')
224 test_request.running_stat = (result[:running_stat][:msg] or '')
225 test_request.running_time = (result[:running_stat][:running_time] or nil)
225 test_request.running_time = (result[:running_stat][:running_time] or nil)
226 test_request.exit_status = result[:running_stat][:exit_status]
226 test_request.exit_status = result[:running_stat][:exit_status]
227 test_request.memory_usage = result[:running_stat][:memory_usage]
227 test_request.memory_usage = result[:running_stat][:memory_usage]
228 else
228 else
229 test_request.running_stat = ''
229 test_request.running_stat = ''
230 end
230 end
231 test_request.save
231 test_request.save
232 end
232 end
233
233
234 protected
234 protected
235 def link_output_file(test_request, fname)
235 def link_output_file(test_request, fname)
236 target_file_name = random_output_file_name(test_request.user,
236 target_file_name = random_output_file_name(test_request.user,
237 test_request.problem)
237 test_request.problem)
238 FileUtils.mkdir_p(File.dirname(target_file_name))
238 FileUtils.mkdir_p(File.dirname(target_file_name))
239 Grader::link_or_copy("#{fname}", "#{target_file_name}")
239 Grader::link_or_copy("#{fname}", "#{target_file_name}")
240 return target_file_name
240 return target_file_name
241 end
241 end
242
242
243 def random_output_file_name(user,problem)
243 def random_output_file_name(user,problem)
244 problem_name = TestRequest.name_of(problem)
244 problem_name = TestRequest.name_of(problem)
245 begin
245 begin
246 tmpname = "#{@config.test_request_output_base_dir}" +
246 tmpname = "#{@config.test_request_output_base_dir}" +
247 "/#{user.login}/#{problem_name}/#{rand(10000)}"
247 "/#{user.login}/#{problem_name}/#{rand(10000)}"
248 end while File.exists?(tmpname)
248 end while File.exists?(tmpname)
249 tmpname
249 tmpname
250 end
250 end
251
251
252 end
252 end
253
253
254 end
254 end
@@ -1,1747 +1,1747
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%dm\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 + 1023) / 1024);
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 ");
1659 ");
1660 exit(2);
1660 exit(2);
1661 }
1661 }
1662
1662
1663 int
1663 int
1664 main(int argc, char **argv)
1664 main(int argc, char **argv)
1665 {
1665 {
1666 int c;
1666 int c;
1667 uid_t uid;
1667 uid_t uid;
1668
1668
1669 while ((c = getopt(argc, argv, "a:c:eE:fi:k:m:M:o:p:r:s:t:Tvw:x:")) >= 0)
1669 while ((c = getopt(argc, argv, "a:c:eE:fi:k:m:M:o:p:r:s:t:Tvw:x:")) >= 0)
1670 switch (c)
1670 switch (c)
1671 {
1671 {
1672 case 'a':
1672 case 'a':
1673 file_access = atol(optarg);
1673 file_access = atol(optarg);
1674 break;
1674 break;
1675 case 'c':
1675 case 'c':
1676 set_cwd = optarg;
1676 set_cwd = optarg;
1677 break;
1677 break;
1678 case 'e':
1678 case 'e':
1679 pass_environ = 1;
1679 pass_environ = 1;
1680 break;
1680 break;
1681 case 'E':
1681 case 'E':
1682 if (!set_env_action(optarg))
1682 if (!set_env_action(optarg))
1683 usage();
1683 usage();
1684 break;
1684 break;
1685 case 'f':
1685 case 'f':
1686 filter_syscalls++;
1686 filter_syscalls++;
1687 break;
1687 break;
1688 case 'k':
1688 case 'k':
1689 stack_limit = atol(optarg);
1689 stack_limit = atol(optarg);
1690 break;
1690 break;
1691 case 'i':
1691 case 'i':
1692 redir_stdin = optarg;
1692 redir_stdin = optarg;
1693 break;
1693 break;
1694 case 'm':
1694 case 'm':
1695 memory_limit = atol(optarg);
1695 memory_limit = atol(optarg);
1696 break;
1696 break;
1697 case 'M':
1697 case 'M':
1698 meta_open(optarg);
1698 meta_open(optarg);
1699 break;
1699 break;
1700 case 'o':
1700 case 'o':
1701 redir_stdout = optarg;
1701 redir_stdout = optarg;
1702 break;
1702 break;
1703 case 'p':
1703 case 'p':
1704 if (!set_path_action(optarg))
1704 if (!set_path_action(optarg))
1705 usage();
1705 usage();
1706 break;
1706 break;
1707 case 'r':
1707 case 'r':
1708 redir_stderr = optarg;
1708 redir_stderr = optarg;
1709 break;
1709 break;
1710 case 's':
1710 case 's':
1711 if (!set_syscall_action(optarg))
1711 if (!set_syscall_action(optarg))
1712 usage();
1712 usage();
1713 break;
1713 break;
1714 case 't':
1714 case 't':
1715 timeout = 1000*atof(optarg);
1715 timeout = 1000*atof(optarg);
1716 break;
1716 break;
1717 case 'T':
1717 case 'T':
1718 syscall_action[__NR_times] = A_YES;
1718 syscall_action[__NR_times] = A_YES;
1719 break;
1719 break;
1720 case 'v':
1720 case 'v':
1721 verbose++;
1721 verbose++;
1722 break;
1722 break;
1723 case 'w':
1723 case 'w':
1724 wall_timeout = 1000*atof(optarg);
1724 wall_timeout = 1000*atof(optarg);
1725 break;
1725 break;
1726 case 'x':
1726 case 'x':
1727 extra_timeout = 1000*atof(optarg);
1727 extra_timeout = 1000*atof(optarg);
1728 break;
1728 break;
1729 default:
1729 default:
1730 usage();
1730 usage();
1731 }
1731 }
1732 if (optind >= argc)
1732 if (optind >= argc)
1733 usage();
1733 usage();
1734
1734
1735 sanity_check();
1735 sanity_check();
1736 uid = geteuid();
1736 uid = geteuid();
1737 if (setreuid(uid, uid) < 0)
1737 if (setreuid(uid, uid) < 0)
1738 die("setreuid: %m");
1738 die("setreuid: %m");
1739 box_pid = fork();
1739 box_pid = fork();
1740 if (box_pid < 0)
1740 if (box_pid < 0)
1741 die("fork: %m");
1741 die("fork: %m");
1742 if (!box_pid)
1742 if (!box_pid)
1743 box_inside(argc-optind, argv+optind);
1743 box_inside(argc-optind, argv+optind);
1744 else
1744 else
1745 boxkeeper();
1745 boxkeeper();
1746 die("Internal error: fell over edge of the world");
1746 die("Internal error: fell over edge of the world");
1747 }
1747 }
@@ -1,133 +1,133
1 #!/usr/bin/env ruby
1 #!/usr/bin/env ruby
2
2
3 CORRECT_MARK = 'P'
3 CORRECT_MARK = 'P'
4 INCORRECT_MARK = '-'
4 INCORRECT_MARK = '-'
5 TIMEOUT_MARK = 'T'
5 TIMEOUT_MARK = 'T'
6 RUN_ERROR_MARK = 'x'
6 RUN_ERROR_MARK = 'x'
7
7
8 def log(str='')
8 def log(str='')
9 if ENV['TALKATIVE']!=nil
9 if ENV['TALKATIVE']!=nil
10 puts str
10 puts str
11 end
11 end
12 if ENV['GRADER_LOGGING']!=nil
12 if ENV['GRADER_LOGGING']!=nil
13 log_fname = ENV['GRADER_LOGGING']
13 log_fname = ENV['GRADER_LOGGING']
14 fp = File.open(log_fname,"a")
14 fp = File.open(log_fname,"a")
15 fp.puts("grade: #{Time.new.strftime("%H:%M")} #{str}")
15 fp.puts("grade: #{Time.new.strftime("%H:%M")} #{str}")
16 fp.close
16 fp.close
17 end
17 end
18 end
18 end
19
19
20 def char_comment(comment)
20 def char_comment(comment)
21 if comment =~ /[Ii]ncorrect/
21 if comment =~ /[Ii]ncorrect/
22 INCORRECT_MARK
22 INCORRECT_MARK
23 elsif comment =~ /[Cc]orrect/
23 elsif comment =~ /[Cc]orrect/
24 CORRECT_MARK
24 CORRECT_MARK
25 elsif comment =~ /[Tt]ime/
25 elsif comment =~ /[Tt]ime/
26 TIMEOUT_MARK
26 TIMEOUT_MARK
27 elsif res = /^[Cc]omment:(.*)$/.match(comment)
27 elsif res = /^[Cc]omment:(.*)$/.match(comment)
28 res[1]
28 res[1]
29 else
29 else
30 RUN_ERROR_MARK # these are run time errors
30 RUN_ERROR_MARK # these are run time errors
31 end
31 end
32 end
32 end
33
33
34 def extract_time(t)
34 def extract_time(t)
35 puts "TIME: #{t}"
35 puts "TIME: #{t}"
36 - if (result=/^(.*)r(.*)u(.*)s(.*)m/.match(t))
36 + if (result=/^(.*)r(.*)u(.*)s(.*)kbytes/.match(t))
37 {:real => result[1], :user => result[2], :sys => result[3], :mem => result[4]}
37 {:real => result[1], :user => result[2], :sys => result[3], :mem => result[4]}
38 else
38 else
39 #{:real => 0, :user => 0, :sys => 0}
39 #{:real => 0, :user => 0, :sys => 0}
40 #puts "ERROR READING RUNNING TIME: #{t}"
40 #puts "ERROR READING RUNNING TIME: #{t}"
41 raise "Error reading running time: #{t}"
41 raise "Error reading running time: #{t}"
42 end
42 end
43 end
43 end
44
44
45 problem_home = ENV['PROBLEM_HOME']
45 problem_home = ENV['PROBLEM_HOME']
46 require "#{problem_home}/script/test_dsl.rb"
46 require "#{problem_home}/script/test_dsl.rb"
47 load "#{problem_home}/test_cases/all_tests.cfg"
47 load "#{problem_home}/test_cases/all_tests.cfg"
48 problem = Problem.get_instance
48 problem = Problem.get_instance
49
49
50 if problem.well_formed? == false
50 if problem.well_formed? == false
51 log "The problem specification is not well formed."
51 log "The problem specification is not well formed."
52 exit(127)
52 exit(127)
53 end
53 end
54
54
55 all_score = 0
55 all_score = 0
56 all_comment = ''
56 all_comment = ''
57 peak_memory = -1
57 peak_memory = -1
58 max_runtime = -1
58 max_runtime = -1
59 (1..(problem.runs.length-1)).each do |k|
59 (1..(problem.runs.length-1)).each do |k|
60 log "grade run #{k}"
60 log "grade run #{k}"
61 run = problem.runs[k]
61 run = problem.runs[k]
62 run_score = nil
62 run_score = nil
63 run_comment = ''
63 run_comment = ''
64 run_comment_short = ''
64 run_comment_short = ''
65 run.tests.each do |test_num|
65 run.tests.each do |test_num|
66 result_file_name = "#{test_num}/result"
66 result_file_name = "#{test_num}/result"
67 if not File.exists?(result_file_name)
67 if not File.exists?(result_file_name)
68 run_comment += "result file for test #{test_num} not found\n"
68 run_comment += "result file for test #{test_num} not found\n"
69 run_comment_short += RUN_ERROR_MARK
69 run_comment_short += RUN_ERROR_MARK
70 log "Cannot find the file #{test_num}/result!"
70 log "Cannot find the file #{test_num}/result!"
71 else
71 else
72 result_file = File.new(result_file_name, "r")
72 result_file = File.new(result_file_name, "r")
73 result_file_lines = result_file.readlines
73 result_file_lines = result_file.readlines
74 if result_file_lines.length>=3
74 if result_file_lines.length>=3
75 current_run_score = result_file_lines[1].to_i
75 current_run_score = result_file_lines[1].to_i
76 run_comment += result_file_lines[0]
76 run_comment += result_file_lines[0]
77 run_comment_short += char_comment(result_file_lines[0].chomp)
77 run_comment_short += char_comment(result_file_lines[0].chomp)
78
78
79 #update max runtime & memory
79 #update max runtime & memory
80 run_stat = extract_time result_file_lines[2]
80 run_stat = extract_time result_file_lines[2]
81 peak_memory = [peak_memory,run_stat[:mem].to_i].max
81 peak_memory = [peak_memory,run_stat[:mem].to_i].max
82 max_runtime = [max_runtime,run_stat[:user].to_f + run_stat[:sys].to_f].max
82 max_runtime = [max_runtime,run_stat[:user].to_f + run_stat[:sys].to_f].max
83 else
83 else
84 current_run_score = 0
84 current_run_score = 0
85 run_comment += "result file for test #{test_num} error\n"
85 run_comment += "result file for test #{test_num} error\n"
86 run_comment_short += RUN_ERROR_MARK
86 run_comment_short += RUN_ERROR_MARK
87 log "Error in #{test_num}/result!"
87 log "Error in #{test_num}/result!"
88 end
88 end
89
89
90 # the score of this run should be the minimum of the score for
90 # the score of this run should be the minimum of the score for
91 # each test case
91 # each test case
92 if (run_score==nil) or (run_score>current_run_score)
92 if (run_score==nil) or (run_score>current_run_score)
93 run_score = current_run_score
93 run_score = current_run_score
94 end
94 end
95 result_file.close
95 result_file.close
96 end
96 end
97 end
97 end
98
98
99 run_result_file = File.new("result-#{k}", "w")
99 run_result_file = File.new("result-#{k}", "w")
100 run_result_file.write run_score
100 run_result_file.write run_score
101 run_result_file.write "\n"
101 run_result_file.write "\n"
102 run_result_file.close
102 run_result_file.close
103
103
104 run_comment_file = File.new("comment-#{k}", "w")
104 run_comment_file = File.new("comment-#{k}", "w")
105 run_comment_file.write "#{run_comment}\n"
105 run_comment_file.write "#{run_comment}\n"
106 run_comment_file.close
106 run_comment_file.close
107
107
108 all_score = all_score + run_score
108 all_score = all_score + run_score
109
109
110 # append comment for test run with many test cases
110 # append comment for test run with many test cases
111 if run.tests.length > 1
111 if run.tests.length > 1
112 run_comment_short = '[' + run_comment_short + ']'
112 run_comment_short = '[' + run_comment_short + ']'
113 end
113 end
114 all_comment += run_comment_short
114 all_comment += run_comment_short
115 end
115 end
116
116
117 result_file = File.new("result", "w")
117 result_file = File.new("result", "w")
118 result_file.write all_score
118 result_file.write all_score
119 result_file.write "\n"
119 result_file.write "\n"
120 result_file.close
120 result_file.close
121
121
122 comment_file = File.new("comment", "w")
122 comment_file = File.new("comment", "w")
123 comment_file.write "#{all_comment}\n"
123 comment_file.write "#{all_comment}\n"
124 comment_file.close
124 comment_file.close
125
125
126
126
127 File.open("run_stat","w") do |file|
127 File.open("run_stat","w") do |file|
128 file.puts max_runtime
128 file.puts max_runtime
129 file.puts peak_memory
129 file.puts peak_memory
130 end
130 end
131
131
132 log "score = #{all_score}\ncomment = #{all_comment}"
132 log "score = #{all_score}\ncomment = #{all_comment}"
133 log "max_runtime = #{max_runtime}\npeak_memory = #{peak_memory}"
133 log "max_runtime = #{max_runtime}\npeak_memory = #{peak_memory}"
You need to be logged in to leave comments. Login now