Description:
merge
Commit status:
[Not Reviewed]
References:
merge java
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r226:befb327cfa39 - - 3 files changed: 194 inserted, 2 deleted

@@ -0,0 +1,179
1 + #!/bin/sh
2 +
3 + echo "This script will install and configure Cafe grader."
4 +
5 + RUBY_VERSION=2.1.2
6 + echo "This will install Ruby $RUBY_VERSION under RVM"
7 +
8 + echo "Installing required apts"
9 +
10 + sudo zypper install \
11 + g++ gcc libmysqlclient18 build-essential \
12 + git-core openssl libreadline6 libreadline6-devel \
13 + zlib1g zlib1g-devel libssl37 libyaml-devel sqlite3-devel \
14 + sqlite3 libxml2-devel libxslt-devel autoconf libc6-devel \
15 + ncurses-devel automake libtool bison subversion \
16 + pkg-config curl nodejs unzip pyflakes java-1_8_0-openjdk \
17 + libmysqld-devel mercurial python-setuptools python-devel
18 +
19 +
20 + echo "Installing Ruby $RUBY_VERSION in RVM"
21 +
22 + rvm install $RUBY_VERSION
23 + rvm use $RUBY_VERSION
24 +
25 + echo "Fetching Cafe Grader from Git repositories"
26 +
27 + echo "Fetching web interface"
28 +
29 + mkdir cafe_grader
30 + cd cafe_grader
31 + #git clone -q git://github.com/jittat/cafe-grader-web.git web
32 + hg clone git+ssh://git@github.com/nattee/cafe-grader-web.git web
33 +
34 + echo "Configuring rails app"
35 +
36 + cp web/config/application.rb.SAMPLE web/config/application.rb
37 + cp web/config/initializers/cafe_grader_config.rb.SAMPLE web/config/initializers/cafe_grader_config.rb
38 +
39 + #replace UTC in application.rb with the system timezone
40 + timezone='UTC'
41 + if [ -f '/etc/timezone' ]; then
42 + timezone=\"`cat /etc/timezone`\"
43 + else
44 + if [ -f '/etc/sysconfig/clock' ]; then
45 + timezone=`grep -e '^TIMEZONE' /etc/sysconfig/clock | grep -o -e '\".*\"'`
46 + fi
47 + fi
48 + replace="s!'UTC'!$timezone!g"
49 + sed -i $replace web/config/application.rb
50 +
51 + echo "At this point we will need MySQL user and database."
52 + echo "Have you created MySQL user and database for Cafe grader? (Y/N) "
53 + read ch
54 +
55 + if [ "$ch" = "n" -o "$ch" = "N" ]
56 + then
57 + echo "Please open another terminal and create the user and database for Cafe grader."
58 + echo "Don't forget to grant access to that database for the user."
59 + echo "Please have username, password, and database name ready before continue."
60 + echo
61 + echo "The following are instructions:"
62 + echo "1. Run mysql:"
63 + echo
64 + echo " mysql -u root -p"
65 + echo
66 + echo " if you have just installed mysql, the root password is the one that you have just entered"
67 + echo "2. Create a new database, a new user, and grant access to grader database:"
68 + echo
69 + echo " create user 'USERNAME'@'localhost' identified by 'PASSWORD';"
70 + echo " create database \`DATABASENEME\`;"
71 + echo " grant all on \`DATABASENAME\`.* to 'USERNAME'@'localhost';"
72 + echo
73 + echo " Replace USERNAME, PASSWORD, and DATABASENAME accordingly."
74 + echo
75 + echo "Hit enter when ready..."
76 + read dummy
77 + fi
78 +
79 + CAFE_PATH=`pwd`
80 +
81 + cd web
82 +
83 + echo "Please provide grader database:"
84 + read database
85 +
86 + echo "Please provide grader username:"
87 + read username
88 +
89 + echo "Please provide $username password:"
90 + read password
91 +
92 + echo "development:" > config/database.yml
93 + echo " adapter: mysql2" >> config/database.yml
94 + echo " encoding: utf8" >> config/database.yml
95 + echo " reconnect: false" >> config/database.yml
96 + echo " database: $database" >> config/database.yml
97 + echo " pool: 5" >> config/database.yml
98 + echo " username: $username" >> config/database.yml
99 + echo " password: $password" >> config/database.yml
100 + echo " host: localhost" >> config/database.yml
101 + echo " socket: /run/mysql/mysql.sock" >> config/database.yml
102 + echo "" >> config/database.yml
103 + echo "production:" >> config/database.yml
104 + echo " adapter: mysql2" >> config/database.yml
105 + echo " encoding: utf8" >> config/database.yml
106 + echo " reconnect: false" >> config/database.yml
107 + echo " database: $database" >> config/database.yml
108 + echo " pool: 5" >> config/database.yml
109 + echo " username: $username" >> config/database.yml
110 + echo " password: $password" >> config/database.yml
111 + echo " host: localhost" >> config/database.yml
112 + echo " socket: /run/mysql/mysql.sock" >> config/database.yml
113 +
114 + echo "Object.instance_eval{remove_const :GRADER_ROOT_DIR}" >> config/initializers/cafe_grader_config.rb
115 + echo "Object.instance_eval{remove_const :GRADING_RESULT_DIR}" >> config/initializers/cafe_grader_config.rb
116 + echo "GRADER_ROOT_DIR = '$CAFE_PATH/judge'" >> config/initializers/cafe_grader_config.rb
117 + echo "GRADING_RESULT_DIR = '$CAFE_PATH/judge/result'" >> config/initializers/cafe_grader_config.rb
118 +
119 + echo "Installing required gems"
120 + gem install bundler
121 + bundle install
122 +
123 + echo "Running rake tasks to initialize database"
124 +
125 + rake db:migrate
126 + rake db:seed
127 +
128 + echo "Running rake tasks to precompile the assets"
129 +
130 + rake assets:precompile
131 +
132 + echo "Intalling web interface complete..."
133 + echo
134 + echo "Fetching grader"
135 +
136 + cd ..
137 +
138 + mkdir judge
139 + cd judge
140 + #git clone -q git://github.com/jittat/cafe-grader-judge-scripts.git scripts
141 + hg clone git+ssh://git@github.com/nattee/cafe-grader-judge-scripts.git scripts
142 + mkdir raw
143 + mkdir ev-exam
144 + mkdir ev
145 + mkdir result
146 + mkdir log
147 +
148 + echo "Configuring grader"
149 +
150 + cp scripts/config/env_exam.rb.SAMPLE scripts/config/env_exam.rb
151 + cp scripts/config/env_grading.rb.SAMPLE scripts/config/env_grading.rb
152 +
153 + # create new environment.rb file
154 + echo "RAILS_ROOT = '$CAFE_PATH/web'" > scripts/config/environment.rb
155 + echo "GRADER_ROOT = '$CAFE_PATH/judge/scripts'" >> scripts/config/environment.rb
156 + echo "require File.join(File.dirname(__FILE__),'../lib/boot')" >> scripts/config/environment.rb
157 + echo "require File.dirname(__FILE__) + \"/env_#{GRADER_ENV}.rb\"" >> scripts/config/environment.rb
158 +
159 + # compiling box
160 + MACHINE_TYPE=`uname -m`
161 + if [ ${MACHINE_TYPE} == 'x86_64' ]; then
162 + gcc -std=c99 -o scripts/std-script/box scripts/std-script/box64-new.c
163 + else
164 + g++ -o scripts/std-script/box scripts/std-script/box.cc
165 + fi
166 +
167 +
168 + cd ..
169 +
170 + echo "Now you are ready to run cafe grader...."
171 + echo
172 + echo "Try:"
173 + echo
174 + echo " cd web"
175 + echo " rails s"
176 + echo
177 + echo "and access web at http://localhost:3000/"
178 + echo "The root username is 'root', its password is 'ioionrails'."
179 +
@@ -1,180 +1,181
1 1 #!/bin/sh
2 2
3 3 echo "This script will install and configure Cafe grader."
4 4
5 5 RUBY_VERSION=2.1.2
6 6 echo "This will install Ruby $RUBY_VERSION under RVM"
7 7
8 8 echo "Installing required apts"
9 9
10 10 sudo apt-get update
11 11 sudo apt-get install mysql-server mysql-client \
12 - g++ gcc apache2 libmysqlclient15-dev build-essential \
12 + g++ gcc apache2 libmysqlclient20 build-essential \
13 13 git-core openssl libreadline6 libreadline6-dev \
14 14 zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev \
15 15 sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev \
16 16 ncurses-dev automake libtool bison subversion \
17 - pkg-config curl nodejs unzip pyflakes ruby default-jdk
17 + pkg-config curl nodejs unzip pyflakes ruby default-jdk \
18 + libmysqld-dev mercurial python-setuptools python-dev python3-numpy
18 19
19 20 echo "Installing RVM"
20 21 curl -k -L https://get.rvm.io | bash -s stable
21 22 source ~/.rvm/scripts/rvm
22 23
23 24 echo "Installing Ruby $RUBY_VERSION in RVM"
24 25
25 26 rvm install $RUBY_VERSION
26 27 rvm use $RUBY_VERSION
27 28
28 29 echo "Fetching Cafe Grader from Git repositories"
29 30
30 31 echo "Fetching web interface"
31 32
32 33 mkdir cafe_grader
33 34 cd cafe_grader
34 35 git clone -q git://github.com/jittat/cafe-grader-web.git web
35 36
36 37 echo "Configuring rails app"
37 38
38 39 cp web/config/application.rb.SAMPLE web/config/application.rb
39 40 cp web/config/initializers/cafe_grader_config.rb.SAMPLE web/config/initializers/cafe_grader_config.rb
40 41
41 42 #replace UTC in application.rb with the system timezone
42 43 timezone='UTC'
43 44 if [ -f '/etc/timezone' ]; then
44 45 timezone=\"`cat /etc/timezone`\"
45 46 else
46 47 if [ -f '/etc/sysconfig/clock' ]; then
47 48 timezone=`grep -e '^TIMEZONE' /etc/sysconfig/clock | grep -o -e '\".*\"'`
48 49 fi
49 50 fi
50 51 replace="s!'UTC'!$timezone!g"
51 52 sed -i $replace web/config/application.rb
52 53
53 54 echo "At this point we will need MySQL user and database."
54 55 echo "Have you created MySQL user and database for Cafe grader? (Y/N) "
55 56 read ch
56 57
57 58 if [ "$ch" = "n" -o "$ch" = "N" ]
58 59 then
59 60 echo "Please open another terminal and create the user and database for Cafe grader."
60 61 echo "Don't forget to grant access to that database for the user."
61 62 echo "Please have username, password, and database name ready before continue."
62 63 echo
63 64 echo "The following are instructions:"
64 65 echo "1. Run mysql:"
65 66 echo
66 67 echo " mysql -u root -p"
67 68 echo
68 69 echo " if you have just installed mysql, the root password is the one that you have just entered"
69 70 echo "2. Create a new database, a new user, and grant access to grader database:"
70 71 echo
71 72 echo " create user 'USERNAME'@'localhost' identified by 'PASSWORD';"
72 73 echo " create database \`DATABASENEME\`;"
73 74 echo " grant all on \`DATABASENAME\`.* to 'USERNAME'@'localhost';"
74 75 echo
75 76 echo " Replace USERNAME, PASSWORD, and DATABASENAME accordingly."
76 77 echo
77 78 echo "Hit enter when ready..."
78 79 read dummy
79 80 fi
80 81
81 82 CAFE_PATH=`pwd`
82 83
83 84 cd web
84 85
85 86 echo "Please provide grader database:"
86 87 read database
87 88
88 89 echo "Please provide grader username:"
89 90 read username
90 91
91 92 echo "Please provide $username password:"
92 93 read password
93 94
94 95 echo "development:" > config/database.yml
95 96 echo " adapter: mysql2" >> config/database.yml
96 97 echo " encoding: utf8" >> config/database.yml
97 98 echo " reconnect: false" >> config/database.yml
98 99 echo " database: $database" >> config/database.yml
99 100 echo " pool: 5" >> config/database.yml
100 101 echo " username: $username" >> config/database.yml
101 102 echo " password: $password" >> config/database.yml
102 103 echo " host: localhost" >> config/database.yml
103 104 echo " socket: /var/run/mysqld/mysqld.sock" >> config/database.yml
104 105 echo "" >> config/database.yml
105 106 echo "production:" >> config/database.yml
106 107 echo " adapter: mysql2" >> config/database.yml
107 108 echo " encoding: utf8" >> config/database.yml
108 109 echo " reconnect: false" >> config/database.yml
109 110 echo " database: $database" >> config/database.yml
110 111 echo " pool: 5" >> config/database.yml
111 112 echo " username: $username" >> config/database.yml
112 113 echo " password: $password" >> config/database.yml
113 114 echo " host: localhost" >> config/database.yml
114 115 echo " socket: /var/run/mysqld/mysqld.sock" >> config/database.yml
115 116
116 117 echo "Object.instance_eval{remove_const :GRADER_ROOT_DIR}" >> config/initializers/cafe_grader_config.rb
117 118 echo "Object.instance_eval{remove_const :GRADING_RESULT_DIR}" >> config/initializers/cafe_grader_config.rb
118 119 echo "GRADER_ROOT_DIR = '$CAFE_PATH/judge'" >> config/initializers/cafe_grader_config.rb
119 120 echo "GRADING_RESULT_DIR = '$CAFE_PATH/judge/result'" >> config/initializers/cafe_grader_config.rb
120 121
121 122 echo "Installing required gems"
122 123 gem install bundler
123 124 bundle install
124 125
125 126 echo "Running rake tasks to initialize database"
126 127
127 128 rake db:migrate
128 129 rake db:seed
129 130
130 131 echo "Running rake tasks to precompile the assets"
131 132
132 133 rake assets:precompile
133 134
134 135 echo "Intalling web interface complete..."
135 136 echo
136 137 echo "Fetching grader"
137 138
138 139 cd ..
139 140
140 141 mkdir judge
141 142 cd judge
142 143 git clone -q git://github.com/jittat/cafe-grader-judge-scripts.git scripts
143 144 mkdir raw
144 145 mkdir ev-exam
145 146 mkdir ev
146 147 mkdir result
147 148 mkdir log
148 149
149 150 echo "Configuring grader"
150 151
151 152 cp scripts/config/env_exam.rb.SAMPLE scripts/config/env_exam.rb
152 153 cp scripts/config/env_grading.rb.SAMPLE scripts/config/env_grading.rb
153 154
154 155 # create new environment.rb file
155 156 echo "RAILS_ROOT = '$CAFE_PATH/web'" > scripts/config/environment.rb
156 157 echo "GRADER_ROOT = '$CAFE_PATH/judge/scripts'" >> scripts/config/environment.rb
157 158 echo "require File.join(File.dirname(__FILE__),'../lib/boot')" >> scripts/config/environment.rb
158 159 echo "require File.dirname(__FILE__) + \"/env_#{GRADER_ENV}.rb\"" >> scripts/config/environment.rb
159 160
160 161 # compiling box
161 162 MACHINE_TYPE=`uname -m`
162 163 if [ ${MACHINE_TYPE} == 'x86_64' ]; then
163 164 gcc -std=c99 -o scripts/std-script/box scripts/std-script/box64-new.c
164 165 else
165 166 g++ -o scripts/std-script/box scripts/std-script/box.cc
166 167 fi
167 168
168 169
169 170 cd ..
170 171
171 172 echo "Now you are ready to run cafe grader...."
172 173 echo
173 174 echo "Try:"
174 175 echo
175 176 echo " cd web"
176 177 echo " rails s"
177 178 echo
178 179 echo "and access web at http://localhost:3000/"
179 180 echo "The root username is 'root', its password is 'ioionrails'."
180 181
@@ -1,1373 +1,1385
1 1 /*
2 2 * A Simple Sandbox for Moe
3 3 *
4 4 * (c) 2001--2010 Martin Mares <mj@ucw.cz>
5 5 */
6 6
7 7 #define _LARGEFILE64_SOURCE
8 8 #define _GNU_SOURCE
9 9
10 10 /* Generated automatically by ./configure, please don't touch manually. */
11 11 #define CONFIG_BOX_KERNEL_AMD64 1
12 12 #define CONFIG_BOX_USER_AMD64 1
13 13 #define CONFIG_DIR "cf"
14 14 #define CONFIG_DIRECT_IO 1
15 15 #define CONFIG_ISOLATE_BOX_DIR "/tmp/box"
16 16 #define CONFIG_ISOLATE_CGROUP_ROOT "/sys/fs/cgroup"
17 17 #define CONFIG_ISOLATE_FIRST_GID 60000
18 18 #define CONFIG_ISOLATE_FIRST_UID 60000
19 19 #define CONFIG_ISOLATE_NUM_BOXES 100
20 20 #define CONFIG_LARGE_FILES 1
21 21 #define CONFIG_LFS 1
22 22 #define CONFIG_LINUX 1
23 23 #define CONFIG_LOCAL 1
24 24 #define CONFIG_UCW_PARTMAP_IS_MMAP 1
25 25 #define CONFIG_UCW_PERL 1
26 26 #define CONFIG_UCW_POOL_IS_MMAP 1
27 27 #define CONFIG_UCW_RADIX_SORTER_BITS 10
28 28 #define CONFIG_UCW_SHELL_UTILS 1
29 29 #define CPU_64BIT_POINTERS 1
30 30 #define CPU_ALLOW_UNALIGNED 1
31 31 #define CPU_AMD64 1
32 32 #define CPU_ARCH "default"
33 33 #define CPU_LITTLE_ENDIAN 1
34 34 #define CPU_PAGE_SIZE 4096
35 35 #define CPU_STRUCT_ALIGN 8
36 36 #define CWARNS_OFF " -Wno-pointer-sign"
37 37 #define HAVE_ASCII_DOC "none"
38 38 #define INSTALL_BIN_DIR "bin"
39 39 #define INSTALL_CONFIG_DIR "cf"
40 40 #define INSTALL_DOC_DIR "share/doc"
41 41 #define INSTALL_INCLUDE_DIR "include"
42 42 #define INSTALL_LIB_DIR "lib"
43 43 #define INSTALL_LOG_DIR "log"
44 44 #define INSTALL_MAN_DIR "share/man"
45 45 #define INSTALL_PERL_DIR "lib/perl5"
46 46 #define INSTALL_PKGCONFIG_DIR "lib/pkgconfig"
47 47 #define INSTALL_PREFIX
48 48 #define INSTALL_RUN_DIR "run"
49 49 #define INSTALL_SBIN_DIR "sbin"
50 50 #define INSTALL_SHARE_DIR "share"
51 51 #define INSTALL_STATE_DIR "lib"
52 52 #define INSTALL_USR_PREFIX
53 53 #define INSTALL_VAR_PREFIX
54 54 #define SHERLOCK_VERSION "3.99.2"
55 55 #define SHERLOCK_VERSION_CODE 3099002
56 56 #define SONAME_PREFIX "lib/"
57 57 #define UCW_VERSION "3.99.2"
58 58 #define UCW_VERSION_CODE 3099002
59 59
60 60 #include <errno.h>
61 61 #include <stdio.h>
62 62 #include <fcntl.h>
63 63 #include <stdlib.h>
64 64 #include <string.h>
65 65 #include <stdarg.h>
66 66 #include <stdint.h>
67 67 #include <unistd.h>
68 68 #include <getopt.h>
69 69 #include <time.h>
70 70 #include <sys/wait.h>
71 71 #include <sys/user.h>
72 72 #include <sys/time.h>
73 73 #include <sys/ptrace.h>
74 74 #include <sys/signal.h>
75 75 #include <sys/sysinfo.h>
76 76 #include <sys/resource.h>
77 77 #include <sys/utsname.h>
78 78 //#include <linux/ptrace.h>
79 79
80 80 #if defined(CONFIG_BOX_KERNEL_AMD64) && !defined(CONFIG_BOX_USER_AMD64)
81 81 #include <asm/unistd_32.h>
82 82 #define NATIVE_NR_execve 59 /* 64-bit execve */
83 83 #else
84 84 #include <asm/unistd.h>
85 85 #define NATIVE_NR_execve __NR_execve
86 86 #endif
87 87
88 88 #define NONRET __attribute__((noreturn))
89 89 #define UNUSED __attribute__((unused))
90 90 #define ARRAY_SIZE(a) (int)(sizeof(a)/sizeof(a[0]))
91 91
92 92 static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */
93 93 static int timeout; /* milliseconds */
94 94 static int wall_timeout;
95 95 static int extra_timeout;
96 96 static int pass_environ;
97 97 static int file_access;
98 98 static int verbose;
99 99 static int memory_limit;
100 100 static int stack_limit;
101 101 static char *redir_stdin, *redir_stdout, *redir_stderr;
102 102 static char *set_cwd;
103 103
104 104 static pid_t box_pid;
105 105 static int is_ptraced;
106 106 static volatile int timer_tick;
107 107 static struct timeval start_time;
108 108 static int ticks_per_sec;
109 109 static int exec_seen;
110 110 static int partial_line;
111 111
112 112 static int mem_peak_kb;
113 113 static int total_ms, wall_ms, sys_ms;
114 114
115 115 static void die(char *msg, ...) NONRET;
116 116 static void sample_mem_peak(void);
117 117
118 118 /*** Meta-files ***/
119 119
120 120 static FILE *metafile;
121 121
122 122 static void
123 123 meta_open(const char *name)
124 124 {
125 125 if (!strcmp(name, "-"))
126 126 {
127 127 metafile = stdout;
128 128 return;
129 129 }
130 130 metafile = fopen(name, "w");
131 131 if (!metafile)
132 132 die("Failed to open metafile '%s'",name);
133 133 }
134 134
135 135 static void
136 136 meta_close(void)
137 137 {
138 138 if (metafile && metafile != stdout)
139 139 fclose(metafile);
140 140 }
141 141
142 142 static void __attribute__((format(printf,1,2)))
143 143 meta_printf(const char *fmt, ...)
144 144 {
145 145 if (!metafile)
146 146 return;
147 147
148 148 va_list args;
149 149 va_start(args, fmt);
150 150 vfprintf(metafile, fmt, args);
151 151 va_end(args);
152 152 }
153 153
154 154
155 155 static void print_running_stat(double wall_time,
156 156 double user_time,
157 157 double system_time,
158 158 int mem_usage)
159 159 {
160 160 //total is user
161 161 //wall is wall
162 162 //
163 163 fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dkbytes\n",
164 164 wall_time, user_time, system_time, mem_usage);
165 165 }
166 166
167 167 static void
168 168 final_stats(struct rusage *rus)
169 169 {
170 170 struct timeval total, now, wall;
171 171 timeradd(&rus->ru_utime, &rus->ru_stime, &total);
172 172 total_ms = total.tv_sec*1000 + total.tv_usec/1000;
173 173 gettimeofday(&now, NULL);
174 174 timersub(&now, &start_time, &wall);
175 175 wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000;
176 176 sys_ms = rus->ru_stime.tv_sec * 1000 + rus->ru_stime.tv_usec / 1000;
177 177
178 178 meta_printf("time:%d.%03d\n", total_ms/1000, total_ms%1000);
179 179 meta_printf("time-wall:%d.%03d\n", wall_ms/1000, wall_ms%1000);
180 180 meta_printf("mem:%llu\n", (unsigned long long) mem_peak_kb * 1024);
181 181 }
182 182
183 183 /*** Messages and exits ***/
184 184
185 185 static void NONRET
186 186 box_exit(int rc)
187 187 {
188 188 if (box_pid > 0)
189 189 {
190 190 sample_mem_peak();
191 191 if (is_ptraced)
192 192 ptrace(PTRACE_KILL, box_pid);
193 193 kill(-box_pid, SIGKILL);
194 194 kill(box_pid, SIGKILL);
195 195 meta_printf("killed:1\n");
196 196
197 197 struct rusage rus;
198 198 int p, stat;
199 199 do
200 200 p = wait4(box_pid, &stat, 0, &rus);
201 201 while (p < 0 && errno == EINTR);
202 202 if (p < 0)
203 203 fprintf(stderr, "UGH: Lost track of the process (%m)\n");
204 204 else {
205 205 final_stats(&rus);
206 206 }
207 207 }
208 208 print_running_stat(
209 209 (double)wall_ms/1000,
210 210 (double)total_ms/1000,
211 211 (double)sys_ms/1000,
212 212 mem_peak_kb);
213 213 meta_close();
214 214 exit(rc);
215 215 }
216 216
217 217 static void
218 218 flush_line(void)
219 219 {
220 220 if (partial_line)
221 221 fputc('\n', stderr);
222 222 partial_line = 0;
223 223 }
224 224
225 225 /* Report an error of the sandbox itself */
226 226 static void NONRET __attribute__((format(printf,1,2)))
227 227 die(char *msg, ...)
228 228 {
229 229 va_list args;
230 230 va_start(args, msg);
231 231 flush_line();
232 232 char buf[1024];
233 233 vsnprintf(buf, sizeof(buf), msg, args);
234 234 meta_printf("status:XX\nmessage:%s\n", buf);
235 235 fputs(buf, stderr);
236 236 fputc('\n', stderr);
237 237 box_exit(2);
238 238 }
239 239
240 240 /* Report an error of the program inside the sandbox */
241 241 static void NONRET __attribute__((format(printf,1,2)))
242 242 err(char *msg, ...)
243 243 {
244 244 va_list args;
245 245 va_start(args, msg);
246 246 flush_line();
247 247 if (msg[0] && msg[1] && msg[2] == ':' && msg[3] == ' ')
248 248 {
249 249 meta_printf("status:%c%c\n", msg[0], msg[1]);
250 250 msg += 4;
251 251 }
252 252 char buf[1024];
253 253 vsnprintf(buf, sizeof(buf), msg, args);
254 254 meta_printf("message:%s\n", buf);
255 255 fputs(buf, stderr);
256 256 fputc('\n', stderr);
257 257 box_exit(1);
258 258 }
259 259
260 260 /* Write a message, but only if in verbose mode */
261 261 static void __attribute__((format(printf,1,2)))
262 262 msg(char *msg, ...)
263 263 {
264 264 va_list args;
265 265 va_start(args, msg);
266 266 if (verbose)
267 267 {
268 268 int len = strlen(msg);
269 269 if (len > 0)
270 270 partial_line = (msg[len-1] != '\n');
271 271 vfprintf(stderr, msg, args);
272 272 fflush(stderr);
273 273 }
274 274 va_end(args);
275 275 }
276 276
277 277 static void *
278 278 xmalloc(size_t size)
279 279 {
280 280 void *p = malloc(size);
281 281 if (!p)
282 282 die("Out of memory");
283 283 return p;
284 284 }
285 285
286 286 /*** Syscall rules ***/
287 287
288 288 static const char * const syscall_names[] = {
289 289
290 290 /* Syscall table automatically generated by mk-syscall-table */
291 291
292 292 /* 0 */ [ __NR_read ] = "read",
293 293 /* 1 */ [ __NR_write ] = "write",
294 294 /* 2 */ [ __NR_open ] = "open",
295 295 /* 3 */ [ __NR_close ] = "close",
296 296 /* 4 */ [ __NR_stat ] = "stat",
297 297 /* 5 */ [ __NR_fstat ] = "fstat",
298 298 /* 6 */ [ __NR_lstat ] = "lstat",
299 299 /* 7 */ [ __NR_poll ] = "poll",
300 300 /* 8 */ [ __NR_lseek ] = "lseek",
301 301 /* 9 */ [ __NR_mmap ] = "mmap",
302 302 /* 10 */ [ __NR_mprotect ] = "mprotect",
303 303 /* 11 */ [ __NR_munmap ] = "munmap",
304 304 /* 12 */ [ __NR_brk ] = "brk",
305 305 /* 13 */ [ __NR_rt_sigaction ] = "rt_sigaction",
306 306 /* 14 */ [ __NR_rt_sigprocmask ] = "rt_sigprocmask",
307 307 /* 15 */ [ __NR_rt_sigreturn ] = "rt_sigreturn",
308 308 /* 16 */ [ __NR_ioctl ] = "ioctl",
309 309 /* 17 */ [ __NR_pread64 ] = "pread64",
310 310 /* 18 */ [ __NR_pwrite64 ] = "pwrite64",
311 311 /* 19 */ [ __NR_readv ] = "readv",
312 312 /* 20 */ [ __NR_writev ] = "writev",
313 313 /* 21 */ [ __NR_access ] = "access",
314 314 /* 22 */ [ __NR_pipe ] = "pipe",
315 315 /* 23 */ [ __NR_select ] = "select",
316 316 /* 24 */ [ __NR_sched_yield ] = "sched_yield",
317 317 /* 25 */ [ __NR_mremap ] = "mremap",
318 318 /* 26 */ [ __NR_msync ] = "msync",
319 319 /* 27 */ [ __NR_mincore ] = "mincore",
320 320 /* 28 */ [ __NR_madvise ] = "madvise",
321 321 /* 29 */ [ __NR_shmget ] = "shmget",
322 322 /* 30 */ [ __NR_shmat ] = "shmat",
323 323 /* 31 */ [ __NR_shmctl ] = "shmctl",
324 324 /* 32 */ [ __NR_dup ] = "dup",
325 325 /* 33 */ [ __NR_dup2 ] = "dup2",
326 326 /* 34 */ [ __NR_pause ] = "pause",
327 327 /* 35 */ [ __NR_nanosleep ] = "nanosleep",
328 328 /* 36 */ [ __NR_getitimer ] = "getitimer",
329 329 /* 37 */ [ __NR_alarm ] = "alarm",
330 330 /* 38 */ [ __NR_setitimer ] = "setitimer",
331 331 /* 39 */ [ __NR_getpid ] = "getpid",
332 332 /* 40 */ [ __NR_sendfile ] = "sendfile",
333 333 /* 41 */ [ __NR_socket ] = "socket",
334 334 /* 42 */ [ __NR_connect ] = "connect",
335 335 /* 43 */ [ __NR_accept ] = "accept",
336 336 /* 44 */ [ __NR_sendto ] = "sendto",
337 337 /* 45 */ [ __NR_recvfrom ] = "recvfrom",
338 338 /* 46 */ [ __NR_sendmsg ] = "sendmsg",
339 339 /* 47 */ [ __NR_recvmsg ] = "recvmsg",
340 340 /* 48 */ [ __NR_shutdown ] = "shutdown",
341 341 /* 49 */ [ __NR_bind ] = "bind",
342 342 /* 50 */ [ __NR_listen ] = "listen",
343 343 /* 51 */ [ __NR_getsockname ] = "getsockname",
344 344 /* 52 */ [ __NR_getpeername ] = "getpeername",
345 345 /* 53 */ [ __NR_socketpair ] = "socketpair",
346 346 /* 54 */ [ __NR_setsockopt ] = "setsockopt",
347 347 /* 55 */ [ __NR_getsockopt ] = "getsockopt",
348 348 /* 56 */ [ __NR_clone ] = "clone",
349 349 /* 57 */ [ __NR_fork ] = "fork",
350 350 /* 58 */ [ __NR_vfork ] = "vfork",
351 351 /* 59 */ [ __NR_execve ] = "execve",
352 352 /* 60 */ [ __NR_exit ] = "exit",
353 353 /* 61 */ [ __NR_wait4 ] = "wait4",
354 354 /* 62 */ [ __NR_kill ] = "kill",
355 355 /* 63 */ [ __NR_uname ] = "uname",
356 356 /* 64 */ [ __NR_semget ] = "semget",
357 357 /* 65 */ [ __NR_semop ] = "semop",
358 358 /* 66 */ [ __NR_semctl ] = "semctl",
359 359 /* 67 */ [ __NR_shmdt ] = "shmdt",
360 360 /* 68 */ [ __NR_msgget ] = "msgget",
361 361 /* 69 */ [ __NR_msgsnd ] = "msgsnd",
362 362 /* 70 */ [ __NR_msgrcv ] = "msgrcv",
363 363 /* 71 */ [ __NR_msgctl ] = "msgctl",
364 364 /* 72 */ [ __NR_fcntl ] = "fcntl",
365 365 /* 73 */ [ __NR_flock ] = "flock",
366 366 /* 74 */ [ __NR_fsync ] = "fsync",
367 367 /* 75 */ [ __NR_fdatasync ] = "fdatasync",
368 368 /* 76 */ [ __NR_truncate ] = "truncate",
369 369 /* 77 */ [ __NR_ftruncate ] = "ftruncate",
370 370 /* 78 */ [ __NR_getdents ] = "getdents",
371 371 /* 79 */ [ __NR_getcwd ] = "getcwd",
372 372 /* 80 */ [ __NR_chdir ] = "chdir",
373 373 /* 81 */ [ __NR_fchdir ] = "fchdir",
374 374 /* 82 */ [ __NR_rename ] = "rename",
375 375 /* 83 */ [ __NR_mkdir ] = "mkdir",
376 376 /* 84 */ [ __NR_rmdir ] = "rmdir",
377 377 /* 85 */ [ __NR_creat ] = "creat",
378 378 /* 86 */ [ __NR_link ] = "link",
379 379 /* 87 */ [ __NR_unlink ] = "unlink",
380 380 /* 88 */ [ __NR_symlink ] = "symlink",
381 381 /* 89 */ [ __NR_readlink ] = "readlink",
382 382 /* 90 */ [ __NR_chmod ] = "chmod",
383 383 /* 91 */ [ __NR_fchmod ] = "fchmod",
384 384 /* 92 */ [ __NR_chown ] = "chown",
385 385 /* 93 */ [ __NR_fchown ] = "fchown",
386 386 /* 94 */ [ __NR_lchown ] = "lchown",
387 387 /* 95 */ [ __NR_umask ] = "umask",
388 388 /* 96 */ [ __NR_gettimeofday ] = "gettimeofday",
389 389 /* 97 */ [ __NR_getrlimit ] = "getrlimit",
390 390 /* 98 */ [ __NR_getrusage ] = "getrusage",
391 391 /* 99 */ [ __NR_sysinfo ] = "sysinfo",
392 392 /* 100 */ [ __NR_times ] = "times",
393 393 /* 101 */ [ __NR_ptrace ] = "ptrace",
394 394 /* 102 */ [ __NR_getuid ] = "getuid",
395 395 /* 103 */ [ __NR_syslog ] = "syslog",
396 396 /* 104 */ [ __NR_getgid ] = "getgid",
397 397 /* 105 */ [ __NR_setuid ] = "setuid",
398 398 /* 106 */ [ __NR_setgid ] = "setgid",
399 399 /* 107 */ [ __NR_geteuid ] = "geteuid",
400 400 /* 108 */ [ __NR_getegid ] = "getegid",
401 401 /* 109 */ [ __NR_setpgid ] = "setpgid",
402 402 /* 110 */ [ __NR_getppid ] = "getppid",
403 403 /* 111 */ [ __NR_getpgrp ] = "getpgrp",
404 404 /* 112 */ [ __NR_setsid ] = "setsid",
405 405 /* 113 */ [ __NR_setreuid ] = "setreuid",
406 406 /* 114 */ [ __NR_setregid ] = "setregid",
407 407 /* 115 */ [ __NR_getgroups ] = "getgroups",
408 408 /* 116 */ [ __NR_setgroups ] = "setgroups",
409 409 /* 117 */ [ __NR_setresuid ] = "setresuid",
410 410 /* 118 */ [ __NR_getresuid ] = "getresuid",
411 411 /* 119 */ [ __NR_setresgid ] = "setresgid",
412 412 /* 120 */ [ __NR_getresgid ] = "getresgid",
413 413 /* 121 */ [ __NR_getpgid ] = "getpgid",
414 414 /* 122 */ [ __NR_setfsuid ] = "setfsuid",
415 415 /* 123 */ [ __NR_setfsgid ] = "setfsgid",
416 416 /* 124 */ [ __NR_getsid ] = "getsid",
417 417 /* 125 */ [ __NR_capget ] = "capget",
418 418 /* 126 */ [ __NR_capset ] = "capset",
419 419 /* 127 */ [ __NR_rt_sigpending ] = "rt_sigpending",
420 420 /* 128 */ [ __NR_rt_sigtimedwait ] = "rt_sigtimedwait",
421 421 /* 129 */ [ __NR_rt_sigqueueinfo ] = "rt_sigqueueinfo",
422 422 /* 130 */ [ __NR_rt_sigsuspend ] = "rt_sigsuspend",
423 423 /* 131 */ [ __NR_sigaltstack ] = "sigaltstack",
424 424 /* 132 */ [ __NR_utime ] = "utime",
425 425 /* 133 */ [ __NR_mknod ] = "mknod",
426 426 /* 134 */ [ __NR_uselib ] = "uselib",
427 427 /* 135 */ [ __NR_personality ] = "personality",
428 428 /* 136 */ [ __NR_ustat ] = "ustat",
429 429 /* 137 */ [ __NR_statfs ] = "statfs",
430 430 /* 138 */ [ __NR_fstatfs ] = "fstatfs",
431 431 /* 139 */ [ __NR_sysfs ] = "sysfs",
432 432 /* 140 */ [ __NR_getpriority ] = "getpriority",
433 433 /* 141 */ [ __NR_setpriority ] = "setpriority",
434 434 /* 142 */ [ __NR_sched_setparam ] = "sched_setparam",
435 435 /* 143 */ [ __NR_sched_getparam ] = "sched_getparam",
436 436 /* 144 */ [ __NR_sched_setscheduler ] = "sched_setscheduler",
437 437 /* 145 */ [ __NR_sched_getscheduler ] = "sched_getscheduler",
438 438 /* 146 */ [ __NR_sched_get_priority_max ] = "sched_get_priority_max",
439 439 /* 147 */ [ __NR_sched_get_priority_min ] = "sched_get_priority_min",
440 440 /* 148 */ [ __NR_sched_rr_get_interval ] = "sched_rr_get_interval",
441 441 /* 149 */ [ __NR_mlock ] = "mlock",
442 442 /* 150 */ [ __NR_munlock ] = "munlock",
443 443 /* 151 */ [ __NR_mlockall ] = "mlockall",
444 444 /* 152 */ [ __NR_munlockall ] = "munlockall",
445 445 /* 153 */ [ __NR_vhangup ] = "vhangup",
446 446 /* 154 */ [ __NR_modify_ldt ] = "modify_ldt",
447 447 /* 155 */ [ __NR_pivot_root ] = "pivot_root",
448 448 /* 156 */ [ __NR__sysctl ] = "_sysctl",
449 449 /* 157 */ [ __NR_prctl ] = "prctl",
450 450 /* 158 */ [ __NR_arch_prctl ] = "arch_prctl",
451 451 /* 159 */ [ __NR_adjtimex ] = "adjtimex",
452 452 /* 160 */ [ __NR_setrlimit ] = "setrlimit",
453 453 /* 161 */ [ __NR_chroot ] = "chroot",
454 454 /* 162 */ [ __NR_sync ] = "sync",
455 455 /* 163 */ [ __NR_acct ] = "acct",
456 456 /* 164 */ [ __NR_settimeofday ] = "settimeofday",
457 457 /* 165 */ [ __NR_mount ] = "mount",
458 458 /* 166 */ [ __NR_umount2 ] = "umount2",
459 459 /* 167 */ [ __NR_swapon ] = "swapon",
460 460 /* 168 */ [ __NR_swapoff ] = "swapoff",
461 461 /* 169 */ [ __NR_reboot ] = "reboot",
462 462 /* 170 */ [ __NR_sethostname ] = "sethostname",
463 463 /* 171 */ [ __NR_setdomainname ] = "setdomainname",
464 464 /* 172 */ [ __NR_iopl ] = "iopl",
465 465 /* 173 */ [ __NR_ioperm ] = "ioperm",
466 466 /* 174 */ [ __NR_create_module ] = "create_module",
467 467 /* 175 */ [ __NR_init_module ] = "init_module",
468 468 /* 176 */ [ __NR_delete_module ] = "delete_module",
469 469 /* 177 */ [ __NR_get_kernel_syms ] = "get_kernel_syms",
470 470 /* 178 */ [ __NR_query_module ] = "query_module",
471 471 /* 179 */ [ __NR_quotactl ] = "quotactl",
472 472 /* 180 */ [ __NR_nfsservctl ] = "nfsservctl",
473 473 /* 181 */ [ __NR_getpmsg ] = "getpmsg",
474 474 /* 182 */ [ __NR_putpmsg ] = "putpmsg",
475 475 /* 183 */ [ __NR_afs_syscall ] = "afs_syscall",
476 476 /* 184 */ [ __NR_tuxcall ] = "tuxcall",
477 477 /* 185 */ [ __NR_security ] = "security",
478 478 /* 186 */ [ __NR_gettid ] = "gettid",
479 479 /* 187 */ [ __NR_readahead ] = "readahead",
480 480 /* 188 */ [ __NR_setxattr ] = "setxattr",
481 481 /* 189 */ [ __NR_lsetxattr ] = "lsetxattr",
482 482 /* 190 */ [ __NR_fsetxattr ] = "fsetxattr",
483 483 /* 191 */ [ __NR_getxattr ] = "getxattr",
484 484 /* 192 */ [ __NR_lgetxattr ] = "lgetxattr",
485 485 /* 193 */ [ __NR_fgetxattr ] = "fgetxattr",
486 486 /* 194 */ [ __NR_listxattr ] = "listxattr",
487 487 /* 195 */ [ __NR_llistxattr ] = "llistxattr",
488 488 /* 196 */ [ __NR_flistxattr ] = "flistxattr",
489 489 /* 197 */ [ __NR_removexattr ] = "removexattr",
490 490 /* 198 */ [ __NR_lremovexattr ] = "lremovexattr",
491 491 /* 199 */ [ __NR_fremovexattr ] = "fremovexattr",
492 492 /* 200 */ [ __NR_tkill ] = "tkill",
493 493 /* 201 */ [ __NR_time ] = "time",
494 494 /* 202 */ [ __NR_futex ] = "futex",
495 495 /* 203 */ [ __NR_sched_setaffinity ] = "sched_setaffinity",
496 496 /* 204 */ [ __NR_sched_getaffinity ] = "sched_getaffinity",
497 497 /* 205 */ [ __NR_set_thread_area ] = "set_thread_area",
498 498 /* 206 */ [ __NR_io_setup ] = "io_setup",
499 499 /* 207 */ [ __NR_io_destroy ] = "io_destroy",
500 500 /* 208 */ [ __NR_io_getevents ] = "io_getevents",
501 501 /* 209 */ [ __NR_io_submit ] = "io_submit",
502 502 /* 210 */ [ __NR_io_cancel ] = "io_cancel",
503 503 /* 211 */ [ __NR_get_thread_area ] = "get_thread_area",
504 504 /* 212 */ [ __NR_lookup_dcookie ] = "lookup_dcookie",
505 505 /* 213 */ [ __NR_epoll_create ] = "epoll_create",
506 506 /* 214 */ [ __NR_epoll_ctl_old ] = "epoll_ctl_old",
507 507 /* 215 */ [ __NR_epoll_wait_old ] = "epoll_wait_old",
508 508 /* 216 */ [ __NR_remap_file_pages ] = "remap_file_pages",
509 509 /* 217 */ [ __NR_getdents64 ] = "getdents64",
510 510 /* 218 */ [ __NR_set_tid_address ] = "set_tid_address",
511 511 /* 219 */ [ __NR_restart_syscall ] = "restart_syscall",
512 512 /* 220 */ [ __NR_semtimedop ] = "semtimedop",
513 513 /* 221 */ [ __NR_fadvise64 ] = "fadvise64",
514 514 /* 222 */ [ __NR_timer_create ] = "timer_create",
515 515 /* 223 */ [ __NR_timer_settime ] = "timer_settime",
516 516 /* 224 */ [ __NR_timer_gettime ] = "timer_gettime",
517 517 /* 225 */ [ __NR_timer_getoverrun ] = "timer_getoverrun",
518 518 /* 226 */ [ __NR_timer_delete ] = "timer_delete",
519 519 /* 227 */ [ __NR_clock_settime ] = "clock_settime",
520 520 /* 228 */ [ __NR_clock_gettime ] = "clock_gettime",
521 521 /* 229 */ [ __NR_clock_getres ] = "clock_getres",
522 522 /* 230 */ [ __NR_clock_nanosleep ] = "clock_nanosleep",
523 523 /* 231 */ [ __NR_exit_group ] = "exit_group",
524 524 /* 232 */ [ __NR_epoll_wait ] = "epoll_wait",
525 525 /* 233 */ [ __NR_epoll_ctl ] = "epoll_ctl",
526 526 /* 234 */ [ __NR_tgkill ] = "tgkill",
527 527 /* 235 */ [ __NR_utimes ] = "utimes",
528 528 /* 236 */ [ __NR_vserver ] = "vserver",
529 529 /* 237 */ [ __NR_mbind ] = "mbind",
530 530 /* 238 */ [ __NR_set_mempolicy ] = "set_mempolicy",
531 531 /* 239 */ [ __NR_get_mempolicy ] = "get_mempolicy",
532 532 /* 240 */ [ __NR_mq_open ] = "mq_open",
533 533 /* 241 */ [ __NR_mq_unlink ] = "mq_unlink",
534 534 /* 242 */ [ __NR_mq_timedsend ] = "mq_timedsend",
535 535 /* 243 */ [ __NR_mq_timedreceive ] = "mq_timedreceive",
536 536 /* 244 */ [ __NR_mq_notify ] = "mq_notify",
537 537 /* 245 */ [ __NR_mq_getsetattr ] = "mq_getsetattr",
538 538 /* 246 */ [ __NR_kexec_load ] = "kexec_load",
539 539 /* 247 */ [ __NR_waitid ] = "waitid",
540 540 /* 248 */ [ __NR_add_key ] = "add_key",
541 541 /* 249 */ [ __NR_request_key ] = "request_key",
542 542 /* 250 */ [ __NR_keyctl ] = "keyctl",
543 543 /* 251 */ [ __NR_ioprio_set ] = "ioprio_set",
544 544 /* 252 */ [ __NR_ioprio_get ] = "ioprio_get",
545 545 /* 253 */ [ __NR_inotify_init ] = "inotify_init",
546 546 /* 254 */ [ __NR_inotify_add_watch ] = "inotify_add_watch",
547 547 /* 255 */ [ __NR_inotify_rm_watch ] = "inotify_rm_watch",
548 548 /* 256 */ [ __NR_migrate_pages ] = "migrate_pages",
549 549 /* 257 */ [ __NR_openat ] = "openat",
550 550 /* 258 */ [ __NR_mkdirat ] = "mkdirat",
551 551 /* 259 */ [ __NR_mknodat ] = "mknodat",
552 552 /* 260 */ [ __NR_fchownat ] = "fchownat",
553 553 /* 261 */ [ __NR_futimesat ] = "futimesat",
554 554 /* 262 */ [ __NR_newfstatat ] = "newfstatat",
555 555 /* 263 */ [ __NR_unlinkat ] = "unlinkat",
556 556 /* 264 */ [ __NR_renameat ] = "renameat",
557 557 /* 265 */ [ __NR_linkat ] = "linkat",
558 558 /* 266 */ [ __NR_symlinkat ] = "symlinkat",
559 559 /* 267 */ [ __NR_readlinkat ] = "readlinkat",
560 560 /* 268 */ [ __NR_fchmodat ] = "fchmodat",
561 561 /* 269 */ [ __NR_faccessat ] = "faccessat",
562 562 /* 270 */ [ __NR_pselect6 ] = "pselect6",
563 563 /* 271 */ [ __NR_ppoll ] = "ppoll",
564 564 /* 272 */ [ __NR_unshare ] = "unshare",
565 565 /* 273 */ [ __NR_set_robust_list ] = "set_robust_list",
566 566 /* 274 */ [ __NR_get_robust_list ] = "get_robust_list",
567 567 /* 275 */ [ __NR_splice ] = "splice",
568 568 /* 276 */ [ __NR_tee ] = "tee",
569 569 /* 277 */ [ __NR_sync_file_range ] = "sync_file_range",
570 570 /* 278 */ [ __NR_vmsplice ] = "vmsplice",
571 571 /* 279 */ [ __NR_move_pages ] = "move_pages",
572 572 /* 280 */ [ __NR_utimensat ] = "utimensat",
573 573 /* 281 */ [ __NR_epoll_pwait ] = "epoll_pwait",
574 574 /* 282 */ [ __NR_signalfd ] = "signalfd",
575 575 /* 283 */ [ __NR_timerfd_create ] = "timerfd_create",
576 576 /* 284 */ [ __NR_eventfd ] = "eventfd",
577 577 /* 285 */ [ __NR_fallocate ] = "fallocate",
578 578 /* 286 */ [ __NR_timerfd_settime ] = "timerfd_settime",
579 579 /* 287 */ [ __NR_timerfd_gettime ] = "timerfd_gettime",
580 580 /* 288 */ [ __NR_accept4 ] = "accept4",
581 581 /* 289 */ [ __NR_signalfd4 ] = "signalfd4",
582 582 /* 290 */ [ __NR_eventfd2 ] = "eventfd2",
583 583 /* 291 */ [ __NR_epoll_create1 ] = "epoll_create1",
584 584 /* 292 */ [ __NR_dup3 ] = "dup3",
585 585 /* 293 */ [ __NR_pipe2 ] = "pipe2",
586 586 /* 294 */ [ __NR_inotify_init1 ] = "inotify_init1",
587 587 /* 295 */ [ __NR_preadv ] = "preadv",
588 588 /* 296 */ [ __NR_pwritev ] = "pwritev",
589 589 /* 297 */ [ __NR_rt_tgsigqueueinfo ] = "rt_tgsigqueueinfo",
590 590 /* 298 */ [ __NR_perf_event_open ] = "perf_event_open",
591 591 /* 299 */ [ __NR_recvmmsg ] = "recvmmsg",
592 592 /* 300 */ [ __NR_fanotify_init ] = "fanotify_init",
593 593 /* 301 */ [ __NR_fanotify_mark ] = "fanotify_mark",
594 594 /* 302 */ [ __NR_prlimit64 ] = "prlimit64",
595 595 /* 303 */ [ __NR_name_to_handle_at ] = "name_to_handle_at",
596 596 /* 304 */ [ __NR_open_by_handle_at ] = "open_by_handle_at",
597 597 /* 305 */ [ __NR_clock_adjtime ] = "clock_adjtime",
598 598 /* 306 */ [ __NR_syncfs ] = "syncfs",
599 599 /* 307 */ [ __NR_sendmmsg ] = "sendmmsg",
600 600 /* 308 */ [ __NR_setns ] = "setns",
601 601 /* 309 */ [ __NR_getcpu ] = "getcpu",
602 602 /* 310 */ [ __NR_process_vm_readv ] = "process_vm_readv",
603 603 /* 311 */ [ __NR_process_vm_writev ] = "process_vm_writev",
604 604 /* 312 */ [ __NR_kcmp ] = "kcmp",
605 605 /* 313 */ [ __NR_finit_module ] = "finit_module",
606 + /* 314 */ [ __NR_sched_setattr ] = "sched_setattr",
607 + /* 315 */ [ __NR_sched_getattr ] = "sched_getattr",
608 + /* 316 */ [ __NR_renameat2 ] = "renameat2",
609 + /* 317 */ [ __NR_seccomp ] = "seccomp",
610 + /* 318 */ [ __NR_getrandom ] = "getrandom",
611 + /* 319 */ [ __NR_memfd_create ] = "memfd_create",
612 + /* 320 */ [ __NR_kexec_file_load ] = "kexec_file_load",
613 + /* 321 */ [ __NR_bpf ] = "bpf",
614 + /* 322 */ [ __NR_execveat ] = "execveat",
615 + /* 323 */ [ __NR_userfaultfd ] = "userfaultfd",
616 + /* 324 */ [ __NR_membarrier ] = "membarrier",
617 + /* 325 */ [ __NR_mlock2 ] = "mlock2",
606 618 };
607 619 #define NUM_SYSCALLS ARRAY_SIZE(syscall_names)
608 620 #define NUM_ACTIONS (NUM_SYSCALLS+64)
609 621
610 622 enum action {
611 623 A_DEFAULT, // Use the default action
612 624 A_NO, // Always forbid
613 625 A_YES, // Always permit
614 626 A_FILENAME, // Permit if arg1 is a known filename
615 627 A_ACTION_MASK = 15,
616 628 A_NO_RETVAL = 32, // Does not return a value
617 629 A_SAMPLE_MEM = 64, // Sample memory usage before the syscall
618 630 A_LIBERAL = 128, // Valid only in liberal mode
619 631 // Must fit in a unsigned char
620 632 };
621 633
622 634 static unsigned char syscall_action[NUM_ACTIONS] = {
623 635 #define S(x) [__NR_##x]
624 636
625 637 // Syscalls permitted for specific file names
626 638 S(open) = A_FILENAME,
627 639 S(creat) = A_FILENAME,
628 640 S(unlink) = A_FILENAME,
629 641 S(access) = A_FILENAME,
630 642 S(truncate) = A_FILENAME,
631 643 S(stat) = A_FILENAME,
632 644 S(lstat) = A_FILENAME,
633 645 S(readlink) = A_FILENAME,
634 646 #ifndef CONFIG_BOX_USER_AMD64
635 647 S(oldstat) = A_FILENAME,
636 648 S(oldlstat) = A_FILENAME,
637 649 S(truncate64) = A_FILENAME,
638 650 S(stat64) = A_FILENAME,
639 651 S(lstat64) = A_FILENAME,
640 652 #endif
641 653
642 654 // Syscalls permitted always
643 655 S(exit) = A_YES | A_SAMPLE_MEM,
644 656 S(read) = A_YES,
645 657 S(write) = A_YES,
646 658 S(close) = A_YES,
647 659 S(lseek) = A_YES,
648 660 S(getpid) = A_YES,
649 661 S(getuid) = A_YES,
650 662 S(dup) = A_YES,
651 663 S(brk) = A_YES,
652 664 S(getgid) = A_YES,
653 665 S(geteuid) = A_YES,
654 666 S(getegid) = A_YES,
655 667 S(dup2) = A_YES,
656 668 S(ftruncate) = A_YES,
657 669 S(fstat) = A_YES,
658 670 S(personality) = A_YES,
659 671 S(readv) = A_YES,
660 672 S(writev) = A_YES,
661 673 S(getresuid) = A_YES,
662 674 #ifdef __NR_pread64
663 675 S(pread64) = A_YES,
664 676 S(pwrite64) = A_YES,
665 677 #else
666 678 S(pread) = A_YES,
667 679 S(pwrite) = A_YES,
668 680 #endif
669 681 S(fcntl) = A_YES,
670 682 S(mmap) = A_YES,
671 683 S(munmap) = A_YES,
672 684 S(ioctl) = A_YES,
673 685 S(uname) = A_YES,
674 686 S(gettid) = A_YES,
675 687 S(set_thread_area) = A_YES,
676 688 S(get_thread_area) = A_YES,
677 689 S(set_tid_address) = A_YES,
678 690 S(exit_group) = A_YES | A_SAMPLE_MEM,
679 691 #ifdef CONFIG_BOX_USER_AMD64
680 692 S(arch_prctl) = A_YES,
681 693 #else
682 694 S(oldfstat) = A_YES,
683 695 S(ftruncate64) = A_YES,
684 696 S(_llseek) = A_YES,
685 697 S(fstat64) = A_YES,
686 698 S(fcntl64) = A_YES,
687 699 S(mmap2) = A_YES,
688 700 #endif
689 701
690 702 // Syscalls permitted only in liberal mode
691 703 S(time) = A_YES | A_LIBERAL,
692 704 S(alarm) = A_YES | A_LIBERAL,
693 705 S(pause) = A_YES | A_LIBERAL,
694 706 S(fchmod) = A_YES | A_LIBERAL,
695 707 S(getrlimit) = A_YES | A_LIBERAL,
696 708 S(getrusage) = A_YES | A_LIBERAL,
697 709 S(gettimeofday) = A_YES | A_LIBERAL,
698 710 S(select) = A_YES | A_LIBERAL,
699 711 S(setitimer) = A_YES | A_LIBERAL,
700 712 S(getitimer) = A_YES | A_LIBERAL,
701 713 S(mprotect) = A_YES | A_LIBERAL,
702 714 S(getdents) = A_YES | A_LIBERAL,
703 715 S(getdents64) = A_YES | A_LIBERAL,
704 716 S(fdatasync) = A_YES | A_LIBERAL,
705 717 S(mremap) = A_YES | A_LIBERAL,
706 718 S(poll) = A_YES | A_LIBERAL,
707 719 S(getcwd) = A_YES | A_LIBERAL,
708 720 S(nanosleep) = A_YES | A_LIBERAL,
709 721 S(rt_sigreturn) = A_YES | A_LIBERAL | A_NO_RETVAL,
710 722 S(rt_sigaction) = A_YES | A_LIBERAL,
711 723 S(rt_sigprocmask) = A_YES | A_LIBERAL,
712 724 S(rt_sigpending) = A_YES | A_LIBERAL,
713 725 S(rt_sigtimedwait) = A_YES | A_LIBERAL,
714 726 S(rt_sigqueueinfo) = A_YES | A_LIBERAL,
715 727 S(rt_sigsuspend) = A_YES | A_LIBERAL,
716 728 S(_sysctl) = A_YES | A_LIBERAL,
717 729 #ifndef CONFIG_BOX_USER_AMD64
718 730 S(sigaction) = A_YES | A_LIBERAL,
719 731 S(sgetmask) = A_YES | A_LIBERAL,
720 732 S(ssetmask) = A_YES | A_LIBERAL,
721 733 S(sigsuspend) = A_YES | A_LIBERAL,
722 734 S(sigpending) = A_YES | A_LIBERAL,
723 735 S(sigreturn) = A_YES | A_LIBERAL | A_NO_RETVAL,
724 736 S(sigprocmask) = A_YES | A_LIBERAL,
725 737 S(ugetrlimit) = A_YES | A_LIBERAL,
726 738 S(readdir) = A_YES | A_LIBERAL,
727 739 S(signal) = A_YES | A_LIBERAL,
728 740 S(_newselect) = A_YES | A_LIBERAL,
729 741 #endif
730 742
731 743 #undef S
732 744 };
733 745
734 746 static const char *
735 747 syscall_name(unsigned int id, char *buf)
736 748 {
737 749 if (id < NUM_SYSCALLS && syscall_names[id])
738 750 return syscall_names[id];
739 751 else
740 752 {
741 753 sprintf(buf, "#%d", id);
742 754 return buf;
743 755 }
744 756 }
745 757
746 758 static int
747 759 syscall_by_name(char *name)
748 760 {
749 761 for (unsigned int i=0; i<NUM_SYSCALLS; i++)
750 762 if (syscall_names[i] && !strcmp(syscall_names[i], name))
751 763 return i;
752 764 if (name[0] == '#')
753 765 name++;
754 766 if (!*name)
755 767 return -1;
756 768 char *ep;
757 769 unsigned long l = strtoul(name, &ep, 0);
758 770 if (*ep)
759 771 return -1;
760 772 if (l >= NUM_ACTIONS)
761 773 return NUM_ACTIONS;
762 774 return l;
763 775 }
764 776
765 777 static int
766 778 set_syscall_action(char *a)
767 779 {
768 780 char *sep = strchr(a, '=');
769 781 enum action act = A_YES;
770 782 if (sep)
771 783 {
772 784 *sep++ = 0;
773 785 if (!strcmp(sep, "yes"))
774 786 act = A_YES;
775 787 else if (!strcmp(sep, "no"))
776 788 act = A_NO;
777 789 else if (!strcmp(sep, "file"))
778 790 act = A_FILENAME;
779 791 else
780 792 return 0;
781 793 }
782 794
783 795 int sys = syscall_by_name(a);
784 796 if (sys < 0)
785 797 die("Unknown syscall `%s'", a);
786 798 if (sys >= NUM_ACTIONS)
787 799 die("Syscall `%s' out of range", a);
788 800 syscall_action[sys] = act;
789 801 return 1;
790 802 }
791 803
792 804 /*** Path rules ***/
793 805
794 806 struct path_rule {
795 807 char *path;
796 808 enum action action;
797 809 struct path_rule *next;
798 810 };
799 811
800 812 static struct path_rule default_path_rules[] = {
801 813 { "/etc/", A_YES },
802 814 { "/lib/", A_YES },
803 815 { "/usr/lib/", A_YES },
804 816 { "/opt/lib/", A_YES },
805 817 { "/usr/share/zoneinfo/", A_YES },
806 818 { "/usr/share/locale/", A_YES },
807 819 { "/dev/null", A_YES },
808 820 { "/dev/zero", A_YES },
809 821 { "/proc/meminfo", A_YES },
810 822 { "/proc/self/stat", A_YES },
811 823 { "/proc/self/exe", A_YES }, // Needed by FPC 2.0.x runtime
812 824 { "/proc/self/maps", A_YES }, // Needed by glibc when it reports arena corruption
813 825 };
814 826
815 827 static struct path_rule *user_path_rules;
816 828 static struct path_rule **last_path_rule = &user_path_rules;
817 829
818 830 static int
819 831 set_path_action(char *a)
820 832 {
821 833 char *sep = strchr(a, '=');
822 834 enum action act = A_YES;
823 835 if (sep)
824 836 {
825 837 *sep++ = 0;
826 838 if (!strcmp(sep, "yes"))
827 839 act = A_YES;
828 840 else if (!strcmp(sep, "no"))
829 841 act = A_NO;
830 842 else
831 843 return 0;
832 844 }
833 845
834 846 struct path_rule *r = xmalloc(sizeof(*r) + strlen(a) + 1);
835 847 r->path = (char *)(r+1);
836 848 strcpy(r->path, a);
837 849 r->action = act;
838 850 r->next = NULL;
839 851 *last_path_rule = r;
840 852 last_path_rule = &r->next;
841 853 return 1;
842 854 }
843 855
844 856 static enum action
845 857 match_path_rule(struct path_rule *r, char *path)
846 858 {
847 859 char *rr = r->path;
848 860 while (*rr)
849 861 if (*rr++ != *path++)
850 862 {
851 863 if (rr[-1] == '/' && !path[-1])
852 864 break;
853 865 return A_DEFAULT;
854 866 }
855 867 if (rr > r->path && rr[-1] != '/' && *path)
856 868 return A_DEFAULT;
857 869 return r->action;
858 870 }
859 871
860 872 /*** Environment rules ***/
861 873
862 874 struct env_rule {
863 875 char *var; // Variable to match
864 876 char *val; // ""=clear, NULL=inherit
865 877 int var_len;
866 878 struct env_rule *next;
867 879 };
868 880
869 881 static struct env_rule *first_env_rule;
870 882 static struct env_rule **last_env_rule = &first_env_rule;
871 883
872 884 static struct env_rule default_env_rules[] = {
873 885 { "LIBC_FATAL_STDERR_", "1" }
874 886 };
875 887
876 888 static int
877 889 set_env_action(char *a0)
878 890 {
879 891 struct env_rule *r = xmalloc(sizeof(*r) + strlen(a0) + 1);
880 892 char *a = (char *)(r+1);
881 893 strcpy(a, a0);
882 894
883 895 char *sep = strchr(a, '=');
884 896 if (sep == a)
885 897 return 0;
886 898 r->var = a;
887 899 if (sep)
888 900 {
889 901 *sep++ = 0;
890 902 r->val = sep;
891 903 }
892 904 else
893 905 r->val = NULL;
894 906 *last_env_rule = r;
895 907 last_env_rule = &r->next;
896 908 r->next = NULL;
897 909 return 1;
898 910 }
899 911
900 912 static int
901 913 match_env_var(char *env_entry, struct env_rule *r)
902 914 {
903 915 if (strncmp(env_entry, r->var, r->var_len))
904 916 return 0;
905 917 return (env_entry[r->var_len] == '=');
906 918 }
907 919
908 920 static void
909 921 apply_env_rule(char **env, int *env_sizep, struct env_rule *r)
910 922 {
911 923 // First remove the variable if already set
912 924 int pos = 0;
913 925 while (pos < *env_sizep && !match_env_var(env[pos], r))
914 926 pos++;
915 927 if (pos < *env_sizep)
916 928 {
917 929 (*env_sizep)--;
918 930 env[pos] = env[*env_sizep];
919 931 env[*env_sizep] = NULL;
920 932 }
921 933
922 934 // What is the new value?
923 935 char *new;
924 936 if (r->val)
925 937 {
926 938 if (!r->val[0])
927 939 return;
928 940 new = xmalloc(r->var_len + 1 + strlen(r->val) + 1);
929 941 sprintf(new, "%s=%s", r->var, r->val);
930 942 }
931 943 else
932 944 {
933 945 pos = 0;
934 946 while (environ[pos] && !match_env_var(environ[pos], r))
935 947 pos++;
936 948 if (!(new = environ[pos]))
937 949 return;
938 950 }
939 951
940 952 // Add it at the end of the array
941 953 env[(*env_sizep)++] = new;
942 954 env[*env_sizep] = NULL;
943 955 }
944 956
945 957 static char **
946 958 setup_environment(void)
947 959 {
948 960 // Link built-in rules with user rules
949 961 for (int i=ARRAY_SIZE(default_env_rules)-1; i >= 0; i--)
950 962 {
951 963 default_env_rules[i].next = first_env_rule;
952 964 first_env_rule = &default_env_rules[i];
953 965 }
954 966
955 967 // Scan the original environment
956 968 char **orig_env = environ;
957 969 int orig_size = 0;
958 970 while (orig_env[orig_size])
959 971 orig_size++;
960 972
961 973 // For each rule, reserve one more slot and calculate length
962 974 int num_rules = 0;
963 975 for (struct env_rule *r = first_env_rule; r; r=r->next)
964 976 {
965 977 num_rules++;
966 978 r->var_len = strlen(r->var);
967 979 }
968 980
969 981 // Create a new environment
970 982 char **env = xmalloc((orig_size + num_rules + 1) * sizeof(char *));
971 983 int size;
972 984 if (pass_environ)
973 985 {
974 986 memcpy(env, environ, orig_size * sizeof(char *));
975 987 size = orig_size;
976 988 }
977 989 else
978 990 size = 0;
979 991 env[size] = NULL;
980 992
981 993 // Apply the rules one by one
982 994 for (struct env_rule *r = first_env_rule; r; r=r->next)
983 995 apply_env_rule(env, &size, r);
984 996
985 997 // Return the new env and pass some gossip
986 998 if (verbose > 1)
987 999 {
988 1000 fprintf(stderr, "Passing environment:\n");
989 1001 for (int i=0; env[i]; i++)
990 1002 fprintf(stderr, "\t%s\n", env[i]);
991 1003 }
992 1004 return env;
993 1005 }
994 1006
995 1007 /*** Low-level parsing of syscalls ***/
996 1008
997 1009 #ifdef CONFIG_BOX_KERNEL_AMD64
998 1010 typedef uint64_t arg_t;
999 1011 #else
1000 1012 typedef uint32_t arg_t;
1001 1013 #endif
1002 1014
1003 1015 struct syscall_args {
1004 1016 arg_t sys;
1005 1017 arg_t arg1, arg2, arg3;
1006 1018 arg_t result;
1007 1019 struct user user;
1008 1020 };
1009 1021
1010 1022 static int user_mem_fd;
1011 1023
1012 1024 static int read_user_mem(arg_t addr, char *buf, int len)
1013 1025 {
1014 1026 if (!user_mem_fd)
1015 1027 {
1016 1028 char memname[64];
1017 1029 sprintf(memname, "/proc/%d/mem", (int) box_pid);
1018 1030 user_mem_fd = open(memname, O_RDONLY);
1019 1031 if (user_mem_fd < 0)
1020 1032 die("open(%s): %m", memname);
1021 1033 }
1022 1034 if (lseek64(user_mem_fd, addr, SEEK_SET) < 0)
1023 1035 die("lseek64(mem): %m");
1024 1036 return read(user_mem_fd, buf, len);
1025 1037 }
1026 1038
1027 1039 static void close_user_mem(void)
1028 1040 {
1029 1041 if (user_mem_fd)
1030 1042 {
1031 1043 close(user_mem_fd);
1032 1044 user_mem_fd = 0;
1033 1045 }
1034 1046 }
1035 1047
1036 1048 #ifdef CONFIG_BOX_KERNEL_AMD64
1037 1049
1038 1050 static void
1039 1051 get_syscall_args(struct syscall_args *a, int is_exit)
1040 1052 {
1041 1053 if (ptrace(PTRACE_GETREGS, box_pid, NULL, &a->user) < 0)
1042 1054 die("ptrace(PTRACE_GETREGS): %m");
1043 1055 a->sys = a->user.regs.orig_rax;
1044 1056 a->result = a->user.regs.rax;
1045 1057
1046 1058 /*
1047 1059 * CAVEAT: We have to check carefully that this is a real 64-bit syscall.
1048 1060 * We test whether the process runs in 64-bit mode, but surprisingly this
1049 1061 * is not enough: a 64-bit process can still issue the INT 0x80 instruction
1050 1062 * which performs a 32-bit syscall. Currently, the only known way how to
1051 1063 * detect this situation is to inspect the instruction code (the kernel
1052 1064 * keeps a syscall type flag internally, but it is not accessible from
1053 1065 * user space). Hopefully, there is no instruction whose suffix is the
1054 1066 * code of the SYSCALL instruction. Sometimes, one would wish the
1055 1067 * instruction codes to be unique even when read backwards :)
1056 1068 */
1057 1069
1058 1070 if (is_exit)
1059 1071 return;
1060 1072
1061 1073 int sys_type;
1062 1074 uint16_t instr;
1063 1075
1064 1076 switch (a->user.regs.cs)
1065 1077 {
1066 1078 case 0x23:
1067 1079 // 32-bit CPU mode => only 32-bit syscalls can be issued
1068 1080 sys_type = 32;
1069 1081 break;
1070 1082 case 0x33:
1071 1083 // 64-bit CPU mode
1072 1084 if (read_user_mem(a->user.regs.rip-2, (char *) &instr, 2) != 2)
1073 1085 err("FO: Cannot read syscall instruction");
1074 1086 switch (instr)
1075 1087 {
1076 1088 case 0x050f:
1077 1089 break;
1078 1090 case 0x80cd:
1079 1091 err("FO: Forbidden 32-bit syscall in 64-bit mode");
1080 1092 default:
1081 1093 err("XX: Unknown syscall instruction %04x", instr);
1082 1094 }
1083 1095 sys_type = 64;
1084 1096 break;
1085 1097 default:
1086 1098 err("XX: Unknown code segment %04jx", (intmax_t) a->user.regs.cs);
1087 1099 }
1088 1100
1089 1101 #ifdef CONFIG_BOX_USER_AMD64
1090 1102 if (sys_type != 64)
1091 1103 err("FO: Forbidden %d-bit mode syscall", sys_type);
1092 1104 #else
1093 1105 if (sys_type != (exec_seen ? 32 : 64))
1094 1106 err("FO: Forbidden %d-bit mode syscall", sys_type);
1095 1107 #endif
1096 1108
1097 1109 if (sys_type == 32)
1098 1110 {
1099 1111 a->arg1 = a->user.regs.rbx;
1100 1112 a->arg2 = a->user.regs.rcx;
1101 1113 a->arg3 = a->user.regs.rdx;
1102 1114 }
1103 1115 else
1104 1116 {
1105 1117 a->arg1 = a->user.regs.rdi;
1106 1118 a->arg2 = a->user.regs.rsi;
1107 1119 a->arg3 = a->user.regs.rdx;
1108 1120 }
1109 1121 }
1110 1122
1111 1123 static void
1112 1124 set_syscall_nr(struct syscall_args *a, arg_t sys)
1113 1125 {
1114 1126 a->sys = sys;
1115 1127 a->user.regs.orig_rax = sys;
1116 1128 if (ptrace(PTRACE_SETREGS, box_pid, NULL, &a->user) < 0)
1117 1129 die("ptrace(PTRACE_SETREGS): %m");
1118 1130 }
1119 1131
1120 1132 static void
1121 1133 sanity_check(void)
1122 1134 {
1123 1135 }
1124 1136
1125 1137 #else
1126 1138
1127 1139 static void
1128 1140 get_syscall_args(struct syscall_args *a, int is_exit UNUSED)
1129 1141 {
1130 1142 if (ptrace(PTRACE_GETREGS, box_pid, NULL, &a->user) < 0)
1131 1143 die("ptrace(PTRACE_GETREGS): %m");
1132 1144 a->sys = a->user.regs.orig_eax;
1133 1145 a->arg1 = a->user.regs.ebx;
1134 1146 a->arg2 = a->user.regs.ecx;
1135 1147 a->arg3 = a->user.regs.edx;
1136 1148 a->result = a->user.regs.eax;
1137 1149 }
1138 1150
1139 1151 static void
1140 1152 set_syscall_nr(struct syscall_args *a, arg_t sys)
1141 1153 {
1142 1154 a->sys = sys;
1143 1155 a->user.regs.orig_eax = sys;
1144 1156 if (ptrace(PTRACE_SETREGS, box_pid, NULL, &a->user) < 0)
1145 1157 die("ptrace(PTRACE_SETREGS): %m");
1146 1158 }
1147 1159
1148 1160 static void
1149 1161 sanity_check(void)
1150 1162 {
1151 1163 #if !defined(CONFIG_BOX_ALLOW_INSECURE)
1152 1164 struct utsname uts;
1153 1165 if (uname(&uts) < 0)
1154 1166 die("uname() failed: %m");
1155 1167
1156 1168 if (!strcmp(uts.machine, "x86_64"))
1157 1169 die("Running 32-bit sandbox on 64-bit kernels is inherently unsafe. Please get a 64-bit version.");
1158 1170 #endif
1159 1171 }
1160 1172
1161 1173 #endif
1162 1174
1163 1175 /*** Syscall checks ***/
1164 1176
1165 1177 static void
1166 1178 valid_filename(arg_t addr)
1167 1179 {
1168 1180 char namebuf[4096], *p, *end;
1169 1181
1170 1182 if (!file_access)
1171 1183 err("FA: File access forbidden");
1172 1184 if (file_access >= 9)
1173 1185 return;
1174 1186
1175 1187 p = end = namebuf;
1176 1188 do
1177 1189 {
1178 1190 if (p >= end)
1179 1191 {
1180 1192 int remains = PAGE_SIZE - (addr & (PAGE_SIZE-1));
1181 1193 int l = namebuf + sizeof(namebuf) - end;
1182 1194 if (l > remains)
1183 1195 l = remains;
1184 1196 if (!l)
1185 1197 err("FA: Access to file with name too long");
1186 1198 remains = read_user_mem(addr, end, l);
1187 1199 if (remains < 0)
1188 1200 die("read(mem): %m");
1189 1201 if (!remains)
1190 1202 err("FA: Access to file with name out of memory");
1191 1203 end += remains;
1192 1204 addr += remains;
1193 1205 }
1194 1206 }
1195 1207 while (*p++);
1196 1208
1197 1209 msg("[%s] ", namebuf);
1198 1210 if (file_access >= 3)
1199 1211 return;
1200 1212
1201 1213 // Everything in current directory is permitted
1202 1214 if (!strchr(namebuf, '/') && strcmp(namebuf, ".."))
1203 1215 return;
1204 1216
1205 1217 // ".." anywhere in the path is forbidden
1206 1218 enum action act = A_DEFAULT;
1207 1219 if (strstr(namebuf, ".."))
1208 1220 act = A_NO;
1209 1221
1210 1222 // Scan user rules
1211 1223 for (struct path_rule *r = user_path_rules; r && !act; r=r->next)
1212 1224 act = match_path_rule(r, namebuf);
1213 1225
1214 1226 // Scan built-in rules
1215 1227 if (file_access >= 2)
1216 1228 for (int i=0; i<ARRAY_SIZE(default_path_rules) && !act; i++)
1217 1229 act = match_path_rule(&default_path_rules[i], namebuf);
1218 1230
1219 1231 if (act != A_YES)
1220 1232 err("FA: Forbidden access to file `%s'", namebuf);
1221 1233 }
1222 1234
1223 1235 // Check syscall. If invalid, return -1, otherwise return the action mask.
1224 1236 static int
1225 1237 valid_syscall(struct syscall_args *a)
1226 1238 {
1227 1239 unsigned int sys = a->sys;
1228 1240 unsigned int act = (sys < NUM_ACTIONS) ? syscall_action[sys] : A_DEFAULT;
1229 1241
1230 1242 if (act & A_LIBERAL)
1231 1243 {
1232 1244 if (filter_syscalls != 1)
1233 1245 act = A_DEFAULT;
1234 1246 }
1235 1247
1236 1248 switch (act & A_ACTION_MASK)
1237 1249 {
1238 1250 case A_YES:
1239 1251 return act;
1240 1252 case A_NO:
1241 1253 return -1;
1242 1254 case A_FILENAME:
1243 1255 valid_filename(a->arg1);
1244 1256 return act;
1245 1257 default: ;
1246 1258 }
1247 1259
1248 1260 switch (sys)
1249 1261 {
1250 1262 case __NR_kill:
1251 1263 if (a->arg1 == (arg_t) box_pid)
1252 1264 {
1253 1265 meta_printf("exitsig:%d\n", (int) a->arg2);
1254 1266 err("SG: Committed suicide by signal %d", (int) a->arg2);
1255 1267 }
1256 1268 return -1;
1257 1269 case __NR_tgkill:
1258 1270 if (a->arg1 == (arg_t) box_pid && a->arg2 == (arg_t) box_pid)
1259 1271 {
1260 1272 meta_printf("exitsig:%d\n", (int) a->arg3);
1261 1273 err("SG: Committed suicide by signal %d", (int) a->arg3);
1262 1274 }
1263 1275 return -1;
1264 1276 default:
1265 1277 return -1;
1266 1278 }
1267 1279 }
1268 1280
1269 1281 static void
1270 1282 signal_alarm(int unused UNUSED)
1271 1283 {
1272 1284 /* Time limit checks are synchronous, so we only schedule them there. */
1273 1285 timer_tick = 1;
1274 1286 alarm(1);
1275 1287 }
1276 1288
1277 1289 static void
1278 1290 signal_int(int unused UNUSED)
1279 1291 {
1280 1292 /* Interrupts are fatal, so no synchronization requirements. */
1281 1293 meta_printf("exitsig:%d\n", SIGINT);
1282 1294 err("SG: Interrupted");
1283 1295 }
1284 1296
1285 1297 #define PROC_BUF_SIZE 4096
1286 1298 static void
1287 1299 read_proc_file(char *buf, char *name, int *fdp)
1288 1300 {
1289 1301 int c;
1290 1302
1291 1303 if (!*fdp)
1292 1304 {
1293 1305 sprintf(buf, "/proc/%d/%s", (int) box_pid, name);
1294 1306 *fdp = open(buf, O_RDONLY);
1295 1307 if (*fdp < 0)
1296 1308 die("open(%s): %m", buf);
1297 1309 }
1298 1310 lseek(*fdp, 0, SEEK_SET);
1299 1311 if ((c = read(*fdp, buf, PROC_BUF_SIZE-1)) < 0)
1300 1312 die("read on /proc/$pid/%s: %m", name);
1301 1313 if (c >= PROC_BUF_SIZE-1)
1302 1314 die("/proc/$pid/%s too long", name);
1303 1315 buf[c] = 0;
1304 1316 }
1305 1317
1306 1318 static void
1307 1319 check_timeout(void)
1308 1320 {
1309 1321 if (wall_timeout)
1310 1322 {
1311 1323 struct timeval now, wall;
1312 1324 int wall_ms;
1313 1325 gettimeofday(&now, NULL);
1314 1326 timersub(&now, &start_time, &wall);
1315 1327 wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000;
1316 1328 if (wall_ms > wall_timeout)
1317 1329 err("TO: Time limit exceeded (wall clock)");
1318 1330 if (verbose > 1)
1319 1331 fprintf(stderr, "[wall time check: %d msec]\n", wall_ms);
1320 1332 }
1321 1333 if (timeout)
1322 1334 {
1323 1335 char buf[PROC_BUF_SIZE], *x;
1324 1336 int utime, stime, ms;
1325 1337 static int proc_stat_fd;
1326 1338 read_proc_file(buf, "stat", &proc_stat_fd);
1327 1339 x = buf;
1328 1340 while (*x && *x != ' ')
1329 1341 x++;
1330 1342 while (*x == ' ')
1331 1343 x++;
1332 1344 if (*x++ != '(')
1333 1345 die("proc stat syntax error 1");
1334 1346 while (*x && (*x != ')' || x[1] != ' '))
1335 1347 x++;
1336 1348 while (*x == ')' || *x == ' ')
1337 1349 x++;
1338 1350 if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
1339 1351 die("proc stat syntax error 2");
1340 1352 ms = (utime + stime) * 1000 / ticks_per_sec;
1341 1353 if (verbose > 1)
1342 1354 fprintf(stderr, "[time check: %d msec]\n", ms);
1343 1355 if (ms > timeout && ms > extra_timeout)
1344 1356 err("TO: Time limit exceeded");
1345 1357 }
1346 1358 }
1347 1359
1348 1360 static void
1349 1361 sample_mem_peak(void)
1350 1362 {
1351 1363 /*
1352 1364 * We want to find out the peak memory usage of the process, which is
1353 1365 * maintained by the kernel, but unforunately it gets lost when the
1354 1366 * process exits (it is not reported in struct rusage). Therefore we
1355 1367 * have to sample it whenever we suspect that the process is about
1356 1368 * to exit.
1357 1369 */
1358 1370 char buf[PROC_BUF_SIZE], *x;
1359 1371 static int proc_status_fd;
1360 1372 read_proc_file(buf, "status", &proc_status_fd);
1361 1373
1362 1374 x = buf;
1363 1375 while (*x)
1364 1376 {
1365 1377 char *key = x;
1366 1378 while (*x && *x != ':' && *x != '\n')
1367 1379 x++;
1368 1380 if (!*x || *x == '\n')
1369 1381 break;
1370 1382 *x++ = 0;
1371 1383 while (*x == ' ' || *x == '\t')
1372 1384 x++;
1373 1385
You need to be logged in to leave comments. Login now