rbx.cp 0.5.73__py3-none-any.whl → 0.6.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rbx/annotations.py +21 -1
- rbx/box/cd.py +11 -1
- rbx/box/checkers.py +9 -1
- rbx/box/cli.py +59 -46
- rbx/box/code.py +142 -3
- rbx/box/contest/build_contest_statements.py +44 -34
- rbx/box/contest/contest_package.py +4 -7
- rbx/box/contest/main.py +7 -58
- rbx/box/contest/schema.py +52 -8
- rbx/box/contest/statements.py +53 -25
- rbx/box/creation.py +3 -36
- rbx/box/environment.py +21 -9
- rbx/box/fields.py +35 -0
- rbx/box/lang.py +27 -0
- rbx/box/linting.py +26 -0
- rbx/box/package.py +4 -35
- rbx/box/packaging/boca/packager.py +48 -5
- rbx/box/packaging/contest_main.py +13 -0
- rbx/box/packaging/main.py +13 -2
- rbx/box/packaging/packager.py +4 -4
- rbx/box/packaging/pkg/packager.py +142 -0
- rbx/box/packaging/polygon/packager.py +2 -24
- rbx/box/packaging/polygon/upload.py +35 -17
- rbx/box/presets/__init__.py +362 -281
- rbx/box/presets/lock_schema.py +1 -2
- rbx/box/presets/schema.py +13 -5
- rbx/box/remote.py +2 -2
- rbx/box/retries.py +8 -0
- rbx/box/schema.py +82 -19
- rbx/box/solutions.py +77 -15
- rbx/box/statements/build_statements.py +44 -27
- rbx/box/statements/builders.py +18 -10
- rbx/box/statements/expander.py +49 -0
- rbx/box/statements/latex_jinja.py +61 -4
- rbx/box/statements/schema.py +33 -9
- rbx/box/stats.py +92 -0
- rbx/box/tasks.py +6 -3
- rbx/box/testcase_utils.py +19 -47
- rbx/box/tooling/__init__.py +0 -0
- rbx/box/tooling/boca/__init__.py +0 -0
- rbx/box/tooling/boca/main.py +13 -0
- rbx/box/tooling/boca/scrape.py +34 -0
- rbx/box/{packaging/boca/upload.py → tooling/boca/scraper.py} +77 -8
- rbx/box/tooling/main.py +8 -0
- rbx/box/ui/utils/run_ui.py +1 -1
- rbx/box/ui/widgets/interaction_box.py +19 -1
- rbx/grading/caching.py +18 -2
- rbx/grading/judge/sandbox.py +60 -5
- rbx/grading/judge/sandboxes/isolate.py +1 -0
- rbx/grading/judge/sandboxes/stupid_sandbox.py +11 -5
- rbx/grading/judge/sandboxes/timeit.py +36 -15
- rbx/grading/processing_context.py +62 -78
- rbx/grading/steps.py +92 -40
- rbx/resources/packagers/boca/checker.sh +4 -1
- rbx/resources/packagers/boca/compile/c +2 -6
- rbx/resources/packagers/boca/compile/cc +2 -6
- rbx/resources/packagers/boca/compile/cpp +2 -6
- rbx/resources/packagers/boca/compile/java +1 -6
- rbx/resources/packagers/boca/compile/kt +24 -28
- rbx/resources/packagers/boca/compile/py2 +2 -6
- rbx/resources/packagers/boca/compile/py3 +2 -6
- rbx/resources/packagers/boca/interactive/c +15 -83
- rbx/resources/packagers/boca/interactive/cc +15 -83
- rbx/resources/packagers/boca/interactive/cpp +15 -83
- rbx/resources/packagers/boca/interactive/java +15 -88
- rbx/resources/packagers/boca/interactive/kt +15 -88
- rbx/resources/packagers/boca/interactive/py2 +15 -88
- rbx/resources/packagers/boca/interactive/py3 +15 -88
- rbx/resources/packagers/boca/interactor_compile.sh +5 -2
- rbx/resources/packagers/boca/interactor_run.sh +174 -0
- rbx/resources/packagers/boca/safeexec.c +530 -0
- rbx/resources/packagers/boca/safeexec_compile.sh +49 -0
- rbx/resources/presets/default/contest/contest.rbx.yml +9 -8
- rbx/resources/presets/default/problem/problem.rbx.yml +38 -26
- rbx/resources/presets/default/problem/random.txt +3 -1
- rbx/resources/presets/default/problem/rbx.h +92 -0
- rbx/resources/presets/default/problem/statement/statement.rbx.tex +4 -7
- rbx/resources/presets/default/problem/validator.cpp +8 -8
- rbx/resources/templates/rbx.h +2 -3
- {rbx_cp-0.5.73.dist-info → rbx_cp-0.6.1.dist-info}/METADATA +23 -6
- {rbx_cp-0.5.73.dist-info → rbx_cp-0.6.1.dist-info}/RECORD +84 -71
- {rbx_cp-0.5.73.dist-info → rbx_cp-0.6.1.dist-info}/WHEEL +1 -1
- rbx/resources/packagers/boca/compile/pas +0 -172
- rbx/resources/presets/default/problem/statement/projecao.png +0 -0
- {rbx_cp-0.5.73.dist-info → rbx_cp-0.6.1.dist-info}/LICENSE +0 -0
- {rbx_cp-0.5.73.dist-info → rbx_cp-0.6.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,530 @@
|
|
1
|
+
/*
|
2
|
+
safeexec
|
3
|
+
Executar um comando num ambiente protegido
|
4
|
+
pbv, 1999-2000
|
5
|
+
alterado por cassio@ime.usp.br 2003-2011
|
6
|
+
|
7
|
+
THIS PROGRAM HAS TO BE INSTALLED WITH SETUID ROOT TO HAVE ALL FUNCTIONS WORKING
|
8
|
+
$ gcc -Wall -o safeexec safeexec.c
|
9
|
+
$ chown root.root safeexec
|
10
|
+
$ chmod 4555 safeexec
|
11
|
+
*/
|
12
|
+
#include <stdlib.h>
|
13
|
+
#include <fcntl.h>
|
14
|
+
#include <stdio.h>
|
15
|
+
#include <unistd.h>
|
16
|
+
#include <glob.h>
|
17
|
+
#include <sys/types.h>
|
18
|
+
#include <sys/stat.h>
|
19
|
+
#include <sys/wait.h>
|
20
|
+
#include <sys/resource.h>
|
21
|
+
#include <signal.h>
|
22
|
+
#include <time.h>
|
23
|
+
|
24
|
+
#include <string.h>
|
25
|
+
#include <errno.h>
|
26
|
+
|
27
|
+
/* tempo de erro entre o sinal e o estouro no caso de time-limit */
|
28
|
+
#define EPSILON 0.01
|
29
|
+
|
30
|
+
#define KBYTE 1024
|
31
|
+
#define MBYTE (KBYTE*KBYTE)
|
32
|
+
|
33
|
+
pid_t child_pid; /* pid of the child process */
|
34
|
+
|
35
|
+
double cpu_timeoutdouble = 5.0;
|
36
|
+
struct rlimit cpu_timeout = {5,5}; /* max cpu time (seconds) */
|
37
|
+
struct rlimit max_nofile = {64,64}; /* max number of open files */
|
38
|
+
struct rlimit max_fsize = {128*MBYTE,128*MBYTE}; /* max filesize */
|
39
|
+
|
40
|
+
struct rlimit max_data = {128*MBYTE, 128*MBYTE}; /* max data segment size */
|
41
|
+
struct rlimit max_core = {0, 0}; /* max core file size */
|
42
|
+
struct rlimit max_rss = {128*MBYTE, 128*MBYTE}; /* max resident set size */
|
43
|
+
|
44
|
+
struct rlimit max_processes = {64,64}; /* max number of processes */
|
45
|
+
|
46
|
+
|
47
|
+
int real_timeout = 30; /* max real time (seconds) */
|
48
|
+
|
49
|
+
int dochroot = 0, st=1;
|
50
|
+
int nruns = 1;
|
51
|
+
int allproc;
|
52
|
+
int killallproc;
|
53
|
+
int bequiet;
|
54
|
+
int checknchild;
|
55
|
+
int user, group;
|
56
|
+
int process_group = 0;
|
57
|
+
const char vers[] = "1.5.1";
|
58
|
+
|
59
|
+
#define BUFFSIZE 256
|
60
|
+
char curdir[BUFFSIZE], rootdir[BUFFSIZE], saida[BUFFSIZE], entrada[BUFFSIZE], erro[BUFFSIZE];
|
61
|
+
|
62
|
+
struct Proc {
|
63
|
+
int uid, pid, ppid, gid, group;
|
64
|
+
unsigned long utime, stime;
|
65
|
+
long cutime, cstime;
|
66
|
+
unsigned long starttime;
|
67
|
+
unsigned long vsize;
|
68
|
+
long rss;
|
69
|
+
long resident, share, text, lib, data;
|
70
|
+
};
|
71
|
+
|
72
|
+
unsigned int getprocs(pid_t ppid, pid_t ppid2, int userid, int groupid, int *nchild, struct Proc **Pr);
|
73
|
+
|
74
|
+
void exitandkill(int ret) {
|
75
|
+
if(killallproc) {
|
76
|
+
if(!bequiet)
|
77
|
+
fprintf(stderr,"safeexec: killing all recent processes from this user/group to avoid possible malicious code... use -K if you don't want this\n");
|
78
|
+
struct Proc *P;
|
79
|
+
unsigned n;
|
80
|
+
int nchild, i;
|
81
|
+
if((n = getprocs(child_pid,getpid(),user,group,&nchild,&P)) > 0) {
|
82
|
+
for(i = 0; i < n; i++) {
|
83
|
+
if(!bequiet)
|
84
|
+
fprintf(stderr,"safeexec: killing processes pid=%d\n", P[i].pid);
|
85
|
+
kill(P[i].pid,9); /* kill children and all processes with userid/groupid that started after us if instructed to do so */
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
switch(ret) {
|
90
|
+
case 8: fprintf(stderr,"safeexec: security threat because strange processes\n"); break;
|
91
|
+
case 7: fprintf(stderr,"safeexec: memory limit exceeded\n"); break;
|
92
|
+
case 5: fprintf(stderr,"safeexec: parameter problem\n"); break;
|
93
|
+
case 6:
|
94
|
+
case 4: fprintf(stderr,"safeexec: ERROR! internal error\n"); break;
|
95
|
+
case 3: fprintf(stderr,"safeexec: time limit exceeded\n"); break;
|
96
|
+
case 2: fprintf(stderr,"safeexec: runtime error\n"); break;
|
97
|
+
case 9: fprintf(stderr,"safeexec: runtime error\n"); break;
|
98
|
+
}
|
99
|
+
exit(ret);
|
100
|
+
}
|
101
|
+
|
102
|
+
unsigned int getprocs(pid_t ppid, pid_t ppid2, int userid, int groupid, int *nchild, struct Proc **Pr) {
|
103
|
+
const int SIZE=10000;
|
104
|
+
char a[SIZE], b[SIZE];
|
105
|
+
unsigned long pidtime=0;
|
106
|
+
glob_t globbuf;
|
107
|
+
unsigned int i, j, k, ki, oldi, n;
|
108
|
+
FILE *tn;
|
109
|
+
struct stat sstat;
|
110
|
+
struct Proc *P, Ptmp;
|
111
|
+
|
112
|
+
glob("/proc/[0-9]*", GLOB_NOSORT, NULL, &globbuf);
|
113
|
+
|
114
|
+
P = calloc(globbuf.gl_pathc, sizeof(struct Proc));
|
115
|
+
if (P == NULL) {
|
116
|
+
if(!bequiet) fprintf(stderr,"safeexec: problem with malloc");
|
117
|
+
exitandkill(4);
|
118
|
+
}
|
119
|
+
*Pr = P;
|
120
|
+
|
121
|
+
for (i = j = 0; i < globbuf.gl_pathc; i++) {
|
122
|
+
snprintf(a, sizeof(a)-1, "%s%s",
|
123
|
+
globbuf.gl_pathv[globbuf.gl_pathc - i - 1], "/stat");
|
124
|
+
snprintf(b, sizeof(b)-1, "%s%s",
|
125
|
+
globbuf.gl_pathv[globbuf.gl_pathc - i - 1], "/statm");
|
126
|
+
#ifdef DEBUG
|
127
|
+
fprintf(stderr,"[opening %s and %s]\n", a,b);
|
128
|
+
#endif
|
129
|
+
tn = fopen(b, "r");
|
130
|
+
if (tn == NULL) continue; /* process vanished since glob() */
|
131
|
+
n = fread(b, 1, SIZE, tn);
|
132
|
+
fclose(tn);
|
133
|
+
tn = fopen(a, "r");
|
134
|
+
if (tn == NULL) continue; /* process vanished since glob() */
|
135
|
+
n = fread(a, 1, SIZE, tn);
|
136
|
+
fstat(fileno(tn), &sstat);
|
137
|
+
P[j].uid = sstat.st_uid;
|
138
|
+
P[j].gid = sstat.st_gid;
|
139
|
+
fclose(tn);
|
140
|
+
|
141
|
+
sscanf(a, "%d %*s %*s %d %d %*s %*s %*s %*s %*s %*s %*s %*s %lu %lu %ld %ld %*s %*s %*s %*s %lu %lu %ld",
|
142
|
+
&P[j].pid,&P[j].ppid,&P[j].group,&P[j].utime,&P[j].stime,&P[j].cutime,&P[j].cstime,&P[j].starttime,&P[j].vsize,&P[j].rss);
|
143
|
+
sscanf(b, "%*s %ld %ld %ld %ld %ld",
|
144
|
+
&P[j].resident,&P[j].share,&P[j].text,&P[j].lib,&P[j].data);
|
145
|
+
if(P[j].pid == ppid2) pidtime = P[j].starttime;
|
146
|
+
#ifdef DEBUG
|
147
|
+
fprintf(stderr,"[check %d,%d,%d,%ld]", P[j].pid, P[j].ppid, P[j].gid, P[j].rss);
|
148
|
+
#endif
|
149
|
+
j++;
|
150
|
+
}
|
151
|
+
|
152
|
+
i = 0;
|
153
|
+
oldi = 1;
|
154
|
+
*nchild = 0;
|
155
|
+
while(i != oldi) {
|
156
|
+
oldi = i;
|
157
|
+
for(k = i; k < j; ++k) {
|
158
|
+
if(P[k].pid != ppid) {
|
159
|
+
for(ki = 0; ki < i; ++ki)
|
160
|
+
if(P[k].ppid == P[ki].pid) {
|
161
|
+
break;
|
162
|
+
}
|
163
|
+
if(ki >= i) {
|
164
|
+
continue;
|
165
|
+
}
|
166
|
+
}
|
167
|
+
Ptmp = P[i];
|
168
|
+
P[i] = P[k];
|
169
|
+
P[k] = Ptmp;
|
170
|
+
++i;
|
171
|
+
}
|
172
|
+
}
|
173
|
+
*nchild = i;
|
174
|
+
while(i < j) {
|
175
|
+
if(P[i].uid != userid || P[i].gid != groupid || P[i].starttime < pidtime || P[i].pid==ppid2) {
|
176
|
+
P[i] = P[--j];
|
177
|
+
} else {
|
178
|
+
if(!bequiet)
|
179
|
+
fprintf(stderr,"safeexec: process %d has user %d, group %d, time %lu, which is suspicious\n",P[i].pid,userid,groupid,P[i].starttime);
|
180
|
+
i++;
|
181
|
+
}
|
182
|
+
}
|
183
|
+
globfree(&globbuf);
|
184
|
+
return i;
|
185
|
+
}
|
186
|
+
|
187
|
+
int testsystem(pid_t p, pid_t pp, int userid, int groupid, double memlim, double rsslim) {
|
188
|
+
struct rusage uso;
|
189
|
+
getrusage(RUSAGE_CHILDREN, &uso);
|
190
|
+
double mem1=0., mem2=0.;
|
191
|
+
struct Proc *P;
|
192
|
+
unsigned n, i;
|
193
|
+
int ret = 1, nchild;
|
194
|
+
n = getprocs(p,pp,userid,groupid,&nchild,&P);
|
195
|
+
if(checknchild) {
|
196
|
+
if(nchild != n) {
|
197
|
+
if(!bequiet) {
|
198
|
+
fprintf(stderr,"\nsafeexec: %d children of this user/group, but list has %d processes (who are the others?).\n",nchild,n);
|
199
|
+
fprintf(stderr,"safeexec: detached children found! Aborting because of possible malicious code... use -a if you don't want this\n");
|
200
|
+
}
|
201
|
+
exitandkill(8);
|
202
|
+
}
|
203
|
+
}
|
204
|
+
if(n > 0) {
|
205
|
+
for(i = 0; i < n; i++) {
|
206
|
+
#ifdef DEBUG
|
207
|
+
fprintf(stderr,"\ndata+stack:%ld, rss:%ld, exe:%ld\n", P[i].data,P[i].rss,P[i].lib+P[i].text+P[i].share);
|
208
|
+
#endif
|
209
|
+
mem2 += (P[i].lib+P[i].text+P[i].share+P[i].data)*getpagesize(); // in pages
|
210
|
+
mem1 += P[i].rss*getpagesize();
|
211
|
+
}
|
212
|
+
#ifdef DEBUG
|
213
|
+
fprintf(stderr,"\nTOTAL rss:%lf, data+stack+exe:%lf\n", mem1, mem2);
|
214
|
+
#endif
|
215
|
+
if(mem2 > memlim || mem1 > rsslim) {
|
216
|
+
if(!bequiet)
|
217
|
+
fprintf(stderr,"\nsafeexec: memory limit exceeded\n");
|
218
|
+
exitandkill(7);
|
219
|
+
}
|
220
|
+
if(nchild == 0) ret = 2;
|
221
|
+
} else {
|
222
|
+
mem1 = ((uso.ru_maxrss+uso.ru_ixrss+uso.ru_idrss+uso.ru_isrss));
|
223
|
+
// fprintf(stderr,"WARNING: controlling only waited-for children! Security issues here if code is not trustful...\n");
|
224
|
+
if(mem1 > memlim) {
|
225
|
+
if(!bequiet)
|
226
|
+
fprintf(stderr,"\nsafeexec: memory limit exceeded of %lfMB\n",memlim/1048576.);
|
227
|
+
exitandkill(7);
|
228
|
+
}
|
229
|
+
ret = 0;
|
230
|
+
}
|
231
|
+
free(P);
|
232
|
+
return ret;
|
233
|
+
}
|
234
|
+
|
235
|
+
char timekill=0;
|
236
|
+
|
237
|
+
/* alarm handler */
|
238
|
+
void handle_alarm(int sig) {
|
239
|
+
static int iter=0;
|
240
|
+
#ifdef DEBUG
|
241
|
+
fprintf(stderr,"parent alarmed\n");
|
242
|
+
#endif
|
243
|
+
testsystem(child_pid,getpid(),allproc?user:-1,allproc?group:-1,max_data.rlim_max,max_rss.rlim_max);
|
244
|
+
if(++iter >= real_timeout) {
|
245
|
+
if(!bequiet)
|
246
|
+
fprintf(stderr, "safeexec: timed-out (realtime) after %d seconds\n", real_timeout);
|
247
|
+
fflush(stderr);
|
248
|
+
timekill=1;
|
249
|
+
kill(child_pid,9); /* kill child */
|
250
|
+
exitandkill(3);
|
251
|
+
}
|
252
|
+
alarm(1); /* set alarm and wait for child execution */
|
253
|
+
}
|
254
|
+
|
255
|
+
void handle_term(int sig) {
|
256
|
+
fprintf(stderr, "safeexec: received SIGTERM\n");
|
257
|
+
kill(child_pid,9);
|
258
|
+
}
|
259
|
+
|
260
|
+
|
261
|
+
void usage(int argc, char **argv) {
|
262
|
+
fprintf(stderr, "safeexec version %s\nusage: %s [ options ] cmd [ arg1 arg2 ... ]\n", vers, argv[0]);
|
263
|
+
fprintf(stderr, "available options are:\n");
|
264
|
+
fprintf(stderr, "\t-c <max core file size> (default: %d)\n",
|
265
|
+
(int) max_core.rlim_max);
|
266
|
+
fprintf(stderr, "\t-f <max file size> (default: %d kbytes)\n",
|
267
|
+
(int) (max_fsize.rlim_max/1024.));
|
268
|
+
fprintf(stderr, "\t-F <max number of files> (default: %d)\n",
|
269
|
+
(int) max_nofile.rlim_max);
|
270
|
+
fprintf(stderr, "\t-d <max process memory> (default: %d kbytes)\n",
|
271
|
+
(int) (max_data.rlim_max/1024.));
|
272
|
+
fprintf(stderr, "\t-m <max process resident memory> (default: %d kbytes)\n",
|
273
|
+
(int) (max_rss.rlim_max/1024.));
|
274
|
+
fprintf(stderr, "\t-u <max number of child procs> (default: %d)\n",
|
275
|
+
(int) max_processes.rlim_max);
|
276
|
+
fprintf(stderr, "\t-t <max cpu time> (default: %d secs)\n",
|
277
|
+
(int) cpu_timeout.rlim_max);
|
278
|
+
fprintf(stderr, "\t-T <max real time> (default: %d secs)\n",
|
279
|
+
(int) real_timeout);
|
280
|
+
fprintf(stderr, "\t-C <actual directory> (default: cwd)\n");
|
281
|
+
fprintf(stderr, "\t-R <root directory> (default: none)\n");
|
282
|
+
fprintf(stderr, "\t-n <chroot it?> (default: %d)\n", dochroot);
|
283
|
+
fprintf(stderr, "\t-r <number of runs?> (default: %d)\n", nruns);
|
284
|
+
fprintf(stderr, "\t-i <standard input file> (default: not defined)\n");
|
285
|
+
fprintf(stderr, "\t-o <standard output file> (default: not defined)\n");
|
286
|
+
fprintf(stderr, "\t-e <standard error file> (default: not defined)\n");
|
287
|
+
fprintf(stderr, "\t-U <user id> (default: %d)\n", user);
|
288
|
+
fprintf(stderr, "\t-G <group id> (default: %d)\n", group);
|
289
|
+
fprintf(stderr, "\t-p <show spent time?> (default: %d)\n", st);
|
290
|
+
fprintf(stderr, "\t-a disable checking all processes (look only to the non-detached children) (default %s)\n", allproc?"enabled":"disabled");
|
291
|
+
fprintf(stderr, "\t-s disable checking existence of detached children (default %s)\n", checknchild?"enabled":"disabled");
|
292
|
+
fprintf(stderr, "\t-K disable killing all processes with user/group id after us (default %s)\n", killallproc?"enabled":"disabled");
|
293
|
+
fprintf(stderr, "\t-q be quiet (default %s)\n", bequiet?"enabled":"disabled");
|
294
|
+
/*******
|
295
|
+
Note that currently Linux does not support strong memory usage limits, so we have
|
296
|
+
to enforce it by checking the amount of memory periodically
|
297
|
+
********/
|
298
|
+
}
|
299
|
+
|
300
|
+
int main(int argc, char **argv) {
|
301
|
+
int status, opt, ret=0;
|
302
|
+
time_t ini;
|
303
|
+
int currun = 0;
|
304
|
+
struct stat sstat;
|
305
|
+
double dt;
|
306
|
+
setvbuf(stderr, NULL, _IONBF, 0);
|
307
|
+
entrada[0] = saida[0] = erro[0] = rootdir[0] = curdir[0] = 0;
|
308
|
+
user = group = -1;
|
309
|
+
allproc = 1;
|
310
|
+
checknchild=1;
|
311
|
+
killallproc=1;
|
312
|
+
bequiet=0;
|
313
|
+
|
314
|
+
if(argc>1 && !strcmp("--help", argv[1])) {
|
315
|
+
usage(argc,argv);
|
316
|
+
exit(5);
|
317
|
+
}
|
318
|
+
|
319
|
+
/* parse command-line options */
|
320
|
+
getcwd(curdir, BUFFSIZE); /* default: use cwd as rootdir */
|
321
|
+
while( (opt=getopt(argc,argv,"qKar:c:d:m:f:F:t:T:u:n:i:o:e:C:R:G:U:p:s:g")) != -1 ) {
|
322
|
+
switch(opt) {
|
323
|
+
case 'q': bequiet=1;
|
324
|
+
break;
|
325
|
+
case 'a': allproc=0;
|
326
|
+
break;
|
327
|
+
case 'K': killallproc=0;
|
328
|
+
break;
|
329
|
+
case 's':
|
330
|
+
checknchild=0;
|
331
|
+
break;
|
332
|
+
case 'c': max_core.rlim_max = max_core.rlim_cur = atoi(optarg);
|
333
|
+
break;
|
334
|
+
case 'f': max_fsize.rlim_max = max_fsize.rlim_cur = KBYTE*atoi(optarg);
|
335
|
+
break;
|
336
|
+
case 'F': max_nofile.rlim_max = max_nofile.rlim_cur = atoi(optarg);
|
337
|
+
break;
|
338
|
+
case 'd': max_data.rlim_max = max_data.rlim_cur = KBYTE*atoi(optarg);
|
339
|
+
break;
|
340
|
+
case 'm': max_rss.rlim_max = max_rss.rlim_cur = KBYTE*atoi(optarg);
|
341
|
+
break;
|
342
|
+
case 't': cpu_timeout.rlim_max = cpu_timeout.rlim_cur = 1 + ((int) atof(optarg));
|
343
|
+
cpu_timeoutdouble = atof(optarg);
|
344
|
+
break;
|
345
|
+
case 'T': real_timeout = atoi(optarg);
|
346
|
+
break;
|
347
|
+
case 'u': max_processes.rlim_max = max_processes.rlim_cur = atoi(optarg);
|
348
|
+
break;
|
349
|
+
case 'U': user = atoi(optarg);
|
350
|
+
break;
|
351
|
+
case 'r': nruns = atoi(optarg);
|
352
|
+
break;
|
353
|
+
case 'G': group = atoi(optarg);
|
354
|
+
break;
|
355
|
+
case 'R': strncpy(rootdir, optarg, 255); /* root directory */
|
356
|
+
rootdir[255]=0;
|
357
|
+
break;
|
358
|
+
case 'C': strncpy(curdir, optarg, 255); /* root directory */
|
359
|
+
curdir[255]=0;
|
360
|
+
break;
|
361
|
+
case 'i': strncpy(entrada, optarg, 255);
|
362
|
+
entrada[255]=0;
|
363
|
+
break;
|
364
|
+
case 'o': strncpy(saida, optarg, 255);
|
365
|
+
saida[255]=0;
|
366
|
+
break;
|
367
|
+
case 'e': strncpy(erro, optarg, 255);
|
368
|
+
erro[255]=0;
|
369
|
+
break;
|
370
|
+
case 'n': dochroot = atoi(optarg);
|
371
|
+
break;
|
372
|
+
case 'p': st = atoi(optarg);
|
373
|
+
break;
|
374
|
+
case '?': usage(argc,argv);
|
375
|
+
exit(5);
|
376
|
+
}
|
377
|
+
}
|
378
|
+
|
379
|
+
if(optind >= argc) { /* no more arguments */
|
380
|
+
usage(argc,argv);
|
381
|
+
exit(5);
|
382
|
+
}
|
383
|
+
|
384
|
+
if(dochroot && chroot(rootdir)) {
|
385
|
+
fprintf(stderr,"ERROR %s\n",strerror(errno));
|
386
|
+
fprintf(stderr,"%s: unable to chroot to directory %s\n",
|
387
|
+
argv[0], rootdir);
|
388
|
+
exit(4);
|
389
|
+
}
|
390
|
+
/* change the root directory (ZP: and working dir, in not root)*/
|
391
|
+
if(curdir[0] && chdir(curdir)) {
|
392
|
+
fprintf(stderr,"ERROR %s\n",strerror(errno));
|
393
|
+
fprintf(stderr,"%s: unable to change directory to %s\n",
|
394
|
+
argv[0], curdir);
|
395
|
+
exit(4);
|
396
|
+
}
|
397
|
+
|
398
|
+
stat(".", &sstat);
|
399
|
+
if(user == -1) {
|
400
|
+
user = (int) sstat.st_uid;
|
401
|
+
if(!bequiet) {
|
402
|
+
fprintf(stderr, "Security note: if the sub-code is not trustful, it shall be run with a different user from the one running safeexec.\
|
403
|
+
Use -U and -G for that, but you might need to have root privilegies.\n");
|
404
|
+
}
|
405
|
+
}
|
406
|
+
if(group == -1)
|
407
|
+
group = (int) sstat.st_gid;
|
408
|
+
if(user == 0 || group == 0) {
|
409
|
+
fprintf(stderr, "ERROR: safeexec shall not be instructed to run the sub-code as root\n");
|
410
|
+
exit(4);
|
411
|
+
}
|
412
|
+
|
413
|
+
time(&ini);
|
414
|
+
dt = 0.;
|
415
|
+
// int iter=0;
|
416
|
+
doagain:
|
417
|
+
if((child_pid=fork())) {
|
418
|
+
struct rusage uso;
|
419
|
+
/* ------------------- parent process ----------------------------- */
|
420
|
+
if(currun == 0) {
|
421
|
+
setrlimit(RLIMIT_CORE, &max_core);
|
422
|
+
}
|
423
|
+
currun++;
|
424
|
+
if(!bequiet)
|
425
|
+
fprintf(stderr,"safeexec: starting the job. Parent controller has pid %d, child is %d...\n",getpid(),child_pid);
|
426
|
+
alarm(1); /* set alarm and wait for child execution */
|
427
|
+
signal(SIGALRM, handle_alarm);
|
428
|
+
signal(SIGTERM, handle_term);
|
429
|
+
while(waitpid(child_pid, &status, 0) != child_pid) ;
|
430
|
+
if(timekill) exitandkill(3);
|
431
|
+
|
432
|
+
testsystem(child_pid,getpid(),allproc?user:-1,allproc?group:-1,max_data.rlim_max,max_rss.rlim_max);
|
433
|
+
|
434
|
+
getrusage(RUSAGE_CHILDREN, &uso);
|
435
|
+
dt = uso.ru_utime.tv_sec+(double)uso.ru_utime.tv_usec/1000000.0+
|
436
|
+
uso.ru_stime.tv_sec+(double)uso.ru_stime.tv_usec/1000000.0;
|
437
|
+
// printf("user runnning time: %.4lf\n",uso.ru_utime.tv_sec+(double)uso.ru_utime.tv_usec/1000000.0);
|
438
|
+
// printf("system runnning time: %.4lf\n",uso.ru_stime.tv_sec+(double)uso.ru_stime.tv_usec/1000000.0);
|
439
|
+
// printf("total runnning time: %.4lf\n",dt);
|
440
|
+
|
441
|
+
if (dt >= cpu_timeoutdouble) {
|
442
|
+
// printf ("utsec=%d utusec=%d stsec=%d stusec=%d\n", uso.ru_utime.tv_sec, uso.ru_utime.tv_usec, uso.ru_stime.tv_sec, uso.ru_stime.tv_usec);
|
443
|
+
if(!bequiet)
|
444
|
+
fprintf(stderr, "safeexec: timed-out (cputime) after %.2lf seconds\n", cpu_timeoutdouble);
|
445
|
+
fflush(stderr);
|
446
|
+
// fprintf(stdout, "timed-out (cputime) after %d seconds\n", cpu_timeoutint);
|
447
|
+
// fflush(stdout);
|
448
|
+
exitandkill(3);
|
449
|
+
}
|
450
|
+
|
451
|
+
// check if child got an uncaught signal error & reproduce it in parent
|
452
|
+
if(WIFSIGNALED(status)) {
|
453
|
+
fprintf (stderr, "safeexec: RUN-TIME SIGNAL REPORTED BY THE PROGRAM %s: %d\n", argv[optind], WTERMSIG(status));
|
454
|
+
fflush(stderr);
|
455
|
+
// raise(WTERMSIG(status));
|
456
|
+
exitandkill(2);
|
457
|
+
}
|
458
|
+
|
459
|
+
if(WIFEXITED(status)) {
|
460
|
+
if(WEXITSTATUS(status)) {
|
461
|
+
ret = WEXITSTATUS(status)+10;
|
462
|
+
if(!bequiet)
|
463
|
+
fprintf (stderr, "safeexec: PROGRAM EXITED WITH NONZERO CODE %s: %d\n",
|
464
|
+
argv[optind], ret-10);
|
465
|
+
} else ret = 0;
|
466
|
+
} else {
|
467
|
+
fprintf (stderr, "safeexec: PROGRAM TERMINATED ABNORMALLY %s\n",
|
468
|
+
argv[optind]);
|
469
|
+
exitandkill(9);
|
470
|
+
}
|
471
|
+
|
472
|
+
if(currun < nruns) goto doagain;
|
473
|
+
|
474
|
+
// otherwise just report the exit code:
|
475
|
+
if (st) fprintf (stderr, "safeexec: TOTAL TIME RUNNING %s: %u sec (%lf sec)\n", argv[optind], (unsigned int) (time(NULL)-ini), dt);
|
476
|
+
exitandkill(ret);
|
477
|
+
} else {
|
478
|
+
/* ------------------- child process ------------------------------ */
|
479
|
+
#ifdef DEBUG
|
480
|
+
fprintf(stderr,"child started\n");
|
481
|
+
#endif
|
482
|
+
/* change the group id to 'nobody' */
|
483
|
+
if(setgid(group)<0) {
|
484
|
+
fprintf(stderr,"ERROR %s\n",strerror(errno));
|
485
|
+
fprintf(stderr, "%s: unable to change gid to %d\n", argv[0], group);
|
486
|
+
exit(4);
|
487
|
+
}
|
488
|
+
/* change the user id to 'nobody' */
|
489
|
+
if(setuid(user)<0) {
|
490
|
+
fprintf(stderr,"ERROR %s\n",strerror(errno));
|
491
|
+
fprintf(stderr, "%s: unable to change uid to %d\n", argv[0], user);
|
492
|
+
exit(4);
|
493
|
+
}
|
494
|
+
|
495
|
+
if(currun==nruns-1) {
|
496
|
+
if (saida[0]) freopen(saida, "w", stdout);
|
497
|
+
if (erro[0]) freopen(erro, "w", stderr);
|
498
|
+
} else {
|
499
|
+
freopen("/dev/null", "w", stdout);
|
500
|
+
freopen("/dev/null", "w", stderr);
|
501
|
+
}
|
502
|
+
if (entrada[0]) freopen(entrada, "r", stdin);
|
503
|
+
|
504
|
+
/* attempt to change the hard limits */
|
505
|
+
/*******Note that currently Linux does not support memory usage limits********/
|
506
|
+
|
507
|
+
cpu_timeout.rlim_max+=1; cpu_timeout.rlim_cur+=1;
|
508
|
+
|
509
|
+
if( setrlimit(RLIMIT_CPU, &cpu_timeout) ||
|
510
|
+
setrlimit(RLIMIT_DATA, &max_data) ||
|
511
|
+
setrlimit(RLIMIT_STACK, &max_data) ||
|
512
|
+
setrlimit(RLIMIT_CORE, &max_core) ||
|
513
|
+
setrlimit(RLIMIT_RSS, &max_rss) ||
|
514
|
+
setrlimit(RLIMIT_FSIZE, &max_fsize) ||
|
515
|
+
setrlimit(RLIMIT_NOFILE, &max_nofile) ||
|
516
|
+
setrlimit(RLIMIT_NPROC, &max_processes) ) {
|
517
|
+
fprintf(stderr,"ERROR %s\n",strerror(errno));
|
518
|
+
fprintf(stderr, "%s: can't set hard limits\n", argv[0]);
|
519
|
+
exit(6);
|
520
|
+
}
|
521
|
+
|
522
|
+
/* attempt to exec the child process */
|
523
|
+
if(execv(argv[optind],&argv[optind]) < 0) {
|
524
|
+
fprintf(stderr,"ERROR %s\n",strerror(errno));
|
525
|
+
fprintf(stderr, "%s: unable to exec %s\n", argv[0], argv[optind]);
|
526
|
+
exit(6);
|
527
|
+
}
|
528
|
+
}
|
529
|
+
return 0;
|
530
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
### START OF SAFEEXEC COMPILATION
|
2
|
+
CACHE_DIR="/tmp/boca-cache"
|
3
|
+
mkdir -p $CACHE_DIR
|
4
|
+
|
5
|
+
# Assumes testlib was added by checker
|
6
|
+
SAFEEXEC_PATH="safeexec.c"
|
7
|
+
SAFEEXEC_OUT="safeexec.exe"
|
8
|
+
|
9
|
+
function LOG() {
|
10
|
+
echo "$*" >&2
|
11
|
+
}
|
12
|
+
|
13
|
+
# find compiler
|
14
|
+
cc=$(which gcc)
|
15
|
+
[ -x "$cc" ] || cc=/usr/bin/gcc
|
16
|
+
if [ ! -x "$cc" ]; then
|
17
|
+
echo "$cc not found or it's not executable"
|
18
|
+
exit 47
|
19
|
+
fi
|
20
|
+
|
21
|
+
read -r -d '' SafeexecContent <<"EOF"
|
22
|
+
{{safeexec_content}}
|
23
|
+
EOF
|
24
|
+
|
25
|
+
printf "%s" "${SafeexecContent}" >$SAFEEXEC_PATH
|
26
|
+
|
27
|
+
safeexec_hash=($(md5sum $SAFEEXEC_PATH))
|
28
|
+
safeexec_cache="$CACHE_DIR/safeexec-${safeexec_hash}"
|
29
|
+
|
30
|
+
echo "Safeexec hash: $safeexec_hash"
|
31
|
+
echo "Copying safeexec to $CDIR/$SAFEEXEC_OUT"
|
32
|
+
if [ -f "$safeexec_cache" ]; then
|
33
|
+
echo "Recovering safeexec from cache: $safeexec_cache"
|
34
|
+
cp "$safeexec_cache" $SAFEEXEC_OUT -f
|
35
|
+
else
|
36
|
+
echo "Compiling safeexec: $SAFEEXEC_PATH"
|
37
|
+
$cc -O2 $SAFEEXEC_PATH -o $SAFEEXEC_OUT
|
38
|
+
|
39
|
+
if [ $? -ne 0 ]; then
|
40
|
+
echo "Safeexec could not be compiled"
|
41
|
+
exit 47
|
42
|
+
fi
|
43
|
+
|
44
|
+
cp $SAFEEXEC_OUT "$safeexec_cache" -f
|
45
|
+
fi
|
46
|
+
|
47
|
+
chown root.root $SAFEEXEC_OUT
|
48
|
+
chmod 4555 $SAFEEXEC_OUT
|
49
|
+
### END OF SAFEEXEC COMPILATION
|
@@ -1,14 +1,15 @@
|
|
1
1
|
# Add problems by running `rbx contest add <problem-name> <short-name>`
|
2
2
|
|
3
3
|
name: "new-contest"
|
4
|
-
statements:
|
5
|
-
-
|
4
|
+
statements:
|
5
|
+
- name: "statement-en"
|
6
|
+
title: "New contest"
|
6
7
|
language: en
|
7
|
-
path:
|
8
|
-
type:
|
9
|
-
assets: [
|
10
|
-
joiner: {type:
|
8
|
+
path: "statement/contest.rbx.tex"
|
9
|
+
type: "jinja-tex"
|
10
|
+
assets: ["statement/olymp.sty", "statement/*.png"]
|
11
|
+
joiner: { type: "tex2pdf" }
|
11
12
|
override:
|
12
13
|
configure:
|
13
|
-
- type:
|
14
|
-
template:
|
14
|
+
- type: "rbx-tex" # Convert rbxTeX to TeX
|
15
|
+
template: "statement/template.rbx.tex"
|
@@ -1,44 +1,56 @@
|
|
1
1
|
# yaml-language-server: $schema=/home/rsalesc/.config/rbx/schemas/Package.json
|
2
2
|
|
3
|
-
name:
|
3
|
+
name: "new-problem"
|
4
4
|
timeLimit: 1000
|
5
5
|
memoryLimit: 256
|
6
|
-
checker: {path:
|
7
|
-
validator: {path:
|
6
|
+
checker: { path: "wcmp.cpp" } # Download others from testlib with `rbx download checker`
|
7
|
+
validator: { path: "validator.cpp" }
|
8
8
|
generators:
|
9
|
-
- path:
|
10
|
-
name:
|
9
|
+
- path: "gen.cpp"
|
10
|
+
name: "gen"
|
11
11
|
testcases:
|
12
|
-
- name:
|
13
|
-
testcaseGlob:
|
14
|
-
- name:
|
12
|
+
- name: "samples"
|
13
|
+
testcaseGlob: "tests/samples/*.in" # Pattern for the sample inputs.
|
14
|
+
- name: "random"
|
15
15
|
generatorScript:
|
16
|
-
path:
|
17
|
-
- name:
|
16
|
+
path: "random.txt" # Static generator script.
|
17
|
+
- name: "program-random"
|
18
18
|
generatorScript:
|
19
|
-
path:
|
19
|
+
path: "random.py" # Generator script written programatically.
|
20
20
|
solutions:
|
21
|
-
- path:
|
21
|
+
- path: "sols/main.cpp"
|
22
22
|
outcome: ACCEPTED
|
23
|
-
- path:
|
23
|
+
- path: "sols/wa.cpp"
|
24
24
|
outcome: WRONG_ANSWER
|
25
|
-
- path:
|
26
|
-
outcome: TLE_OR_RTE
|
25
|
+
- path: "sols/slow.cpp"
|
26
|
+
outcome: TLE_OR_RTE # Can be TLE too
|
27
27
|
statements:
|
28
|
-
-
|
29
|
-
|
28
|
+
- name: "statement-en"
|
29
|
+
title: "New Problem"
|
30
|
+
path: "statement/statement.rbx.tex" # Open this file to edit your statement.
|
30
31
|
type: rbxTeX
|
31
|
-
language:
|
32
|
-
assets: [
|
32
|
+
language: "en"
|
33
|
+
assets: ["statement/olymp.sty", "statement/*.png"]
|
33
34
|
configure:
|
34
|
-
- type:
|
35
|
-
template:
|
35
|
+
- type: "rbx-tex" # Convert rbxTeX to TeX
|
36
|
+
template: "statement/template.rbx.tex"
|
36
37
|
stresses:
|
37
|
-
- name:
|
38
|
+
- name: "stress"
|
38
39
|
generator:
|
39
|
-
name:
|
40
|
-
args:
|
41
|
-
finder:
|
40
|
+
name: "gen"
|
41
|
+
args: "[1..<MAX_N>] @" # `@` generates a random string
|
42
|
+
finder: "[sols/wa.cpp] ~ INCORRECT"
|
43
|
+
unitTests:
|
44
|
+
validator:
|
45
|
+
- glob: "unit/validator/valid*.in"
|
46
|
+
outcome: "VALID"
|
47
|
+
- glob: "unit/validator/invalid*.in"
|
48
|
+
outcome: "INVALID"
|
49
|
+
checker:
|
50
|
+
- glob: "unit/checker/ac*"
|
51
|
+
outcome: "ACCEPTED"
|
52
|
+
- glob: "unit/checker/wa*"
|
53
|
+
outcome: "WRONG_ANSWER"
|
42
54
|
vars:
|
43
|
-
"MAX_N": 1000000000
|
55
|
+
"MAX_N": 1000000000 # Can be used in the validator, in stress tests and in the statement.
|
44
56
|
|