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.
Files changed (86) hide show
  1. rbx/annotations.py +21 -1
  2. rbx/box/cd.py +11 -1
  3. rbx/box/checkers.py +9 -1
  4. rbx/box/cli.py +59 -46
  5. rbx/box/code.py +142 -3
  6. rbx/box/contest/build_contest_statements.py +44 -34
  7. rbx/box/contest/contest_package.py +4 -7
  8. rbx/box/contest/main.py +7 -58
  9. rbx/box/contest/schema.py +52 -8
  10. rbx/box/contest/statements.py +53 -25
  11. rbx/box/creation.py +3 -36
  12. rbx/box/environment.py +21 -9
  13. rbx/box/fields.py +35 -0
  14. rbx/box/lang.py +27 -0
  15. rbx/box/linting.py +26 -0
  16. rbx/box/package.py +4 -35
  17. rbx/box/packaging/boca/packager.py +48 -5
  18. rbx/box/packaging/contest_main.py +13 -0
  19. rbx/box/packaging/main.py +13 -2
  20. rbx/box/packaging/packager.py +4 -4
  21. rbx/box/packaging/pkg/packager.py +142 -0
  22. rbx/box/packaging/polygon/packager.py +2 -24
  23. rbx/box/packaging/polygon/upload.py +35 -17
  24. rbx/box/presets/__init__.py +362 -281
  25. rbx/box/presets/lock_schema.py +1 -2
  26. rbx/box/presets/schema.py +13 -5
  27. rbx/box/remote.py +2 -2
  28. rbx/box/retries.py +8 -0
  29. rbx/box/schema.py +82 -19
  30. rbx/box/solutions.py +77 -15
  31. rbx/box/statements/build_statements.py +44 -27
  32. rbx/box/statements/builders.py +18 -10
  33. rbx/box/statements/expander.py +49 -0
  34. rbx/box/statements/latex_jinja.py +61 -4
  35. rbx/box/statements/schema.py +33 -9
  36. rbx/box/stats.py +92 -0
  37. rbx/box/tasks.py +6 -3
  38. rbx/box/testcase_utils.py +19 -47
  39. rbx/box/tooling/__init__.py +0 -0
  40. rbx/box/tooling/boca/__init__.py +0 -0
  41. rbx/box/tooling/boca/main.py +13 -0
  42. rbx/box/tooling/boca/scrape.py +34 -0
  43. rbx/box/{packaging/boca/upload.py → tooling/boca/scraper.py} +77 -8
  44. rbx/box/tooling/main.py +8 -0
  45. rbx/box/ui/utils/run_ui.py +1 -1
  46. rbx/box/ui/widgets/interaction_box.py +19 -1
  47. rbx/grading/caching.py +18 -2
  48. rbx/grading/judge/sandbox.py +60 -5
  49. rbx/grading/judge/sandboxes/isolate.py +1 -0
  50. rbx/grading/judge/sandboxes/stupid_sandbox.py +11 -5
  51. rbx/grading/judge/sandboxes/timeit.py +36 -15
  52. rbx/grading/processing_context.py +62 -78
  53. rbx/grading/steps.py +92 -40
  54. rbx/resources/packagers/boca/checker.sh +4 -1
  55. rbx/resources/packagers/boca/compile/c +2 -6
  56. rbx/resources/packagers/boca/compile/cc +2 -6
  57. rbx/resources/packagers/boca/compile/cpp +2 -6
  58. rbx/resources/packagers/boca/compile/java +1 -6
  59. rbx/resources/packagers/boca/compile/kt +24 -28
  60. rbx/resources/packagers/boca/compile/py2 +2 -6
  61. rbx/resources/packagers/boca/compile/py3 +2 -6
  62. rbx/resources/packagers/boca/interactive/c +15 -83
  63. rbx/resources/packagers/boca/interactive/cc +15 -83
  64. rbx/resources/packagers/boca/interactive/cpp +15 -83
  65. rbx/resources/packagers/boca/interactive/java +15 -88
  66. rbx/resources/packagers/boca/interactive/kt +15 -88
  67. rbx/resources/packagers/boca/interactive/py2 +15 -88
  68. rbx/resources/packagers/boca/interactive/py3 +15 -88
  69. rbx/resources/packagers/boca/interactor_compile.sh +5 -2
  70. rbx/resources/packagers/boca/interactor_run.sh +174 -0
  71. rbx/resources/packagers/boca/safeexec.c +530 -0
  72. rbx/resources/packagers/boca/safeexec_compile.sh +49 -0
  73. rbx/resources/presets/default/contest/contest.rbx.yml +9 -8
  74. rbx/resources/presets/default/problem/problem.rbx.yml +38 -26
  75. rbx/resources/presets/default/problem/random.txt +3 -1
  76. rbx/resources/presets/default/problem/rbx.h +92 -0
  77. rbx/resources/presets/default/problem/statement/statement.rbx.tex +4 -7
  78. rbx/resources/presets/default/problem/validator.cpp +8 -8
  79. rbx/resources/templates/rbx.h +2 -3
  80. {rbx_cp-0.5.73.dist-info → rbx_cp-0.6.1.dist-info}/METADATA +23 -6
  81. {rbx_cp-0.5.73.dist-info → rbx_cp-0.6.1.dist-info}/RECORD +84 -71
  82. {rbx_cp-0.5.73.dist-info → rbx_cp-0.6.1.dist-info}/WHEEL +1 -1
  83. rbx/resources/packagers/boca/compile/pas +0 -172
  84. rbx/resources/presets/default/problem/statement/projecao.png +0 -0
  85. {rbx_cp-0.5.73.dist-info → rbx_cp-0.6.1.dist-info}/LICENSE +0 -0
  86. {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
- - title: "New contest"
4
+ statements:
5
+ - name: "statement-en"
6
+ title: "New contest"
6
7
  language: en
7
- path: 'statement/contest.rbx.tex'
8
- type: 'jinja-tex'
9
- assets: ['statement/olymp.sty', 'statement/*.png']
10
- joiner: {type: 'tex2pdf'}
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: 'rbx-tex' # Convert rbxTeX to TeX
14
- template: 'statement/template.rbx.tex'
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: 'new-problem'
3
+ name: "new-problem"
4
4
  timeLimit: 1000
5
5
  memoryLimit: 256
6
- checker: {path: 'wcmp.cpp'} # Download others from testlib with `rbx download checker`
7
- validator: {path: 'validator.cpp'}
6
+ checker: { path: "wcmp.cpp" } # Download others from testlib with `rbx download checker`
7
+ validator: { path: "validator.cpp" }
8
8
  generators:
9
- - path: 'gen.cpp'
10
- name: 'gen'
9
+ - path: "gen.cpp"
10
+ name: "gen"
11
11
  testcases:
12
- - name: 'samples'
13
- testcaseGlob: 'tests/samples/*.in' # Pattern for the sample inputs.
14
- - name: 'random'
12
+ - name: "samples"
13
+ testcaseGlob: "tests/samples/*.in" # Pattern for the sample inputs.
14
+ - name: "random"
15
15
  generatorScript:
16
- path: 'random.txt' # Static generator script.
17
- - name: 'program-random'
16
+ path: "random.txt" # Static generator script.
17
+ - name: "program-random"
18
18
  generatorScript:
19
- path: 'random.py' # Generator script written programatically.
19
+ path: "random.py" # Generator script written programatically.
20
20
  solutions:
21
- - path: 'sols/main.cpp'
21
+ - path: "sols/main.cpp"
22
22
  outcome: ACCEPTED
23
- - path: 'sols/wa.cpp'
23
+ - path: "sols/wa.cpp"
24
24
  outcome: WRONG_ANSWER
25
- - path: 'sols/slow.cpp'
26
- outcome: TLE_OR_RTE # Can be TLE too
25
+ - path: "sols/slow.cpp"
26
+ outcome: TLE_OR_RTE # Can be TLE too
27
27
  statements:
28
- - title: 'New Problem'
29
- path: 'statement/statement.rbx.tex' # Open this file to edit your statement.
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: 'en'
32
- assets: ['statement/olymp.sty', 'statement/*.png']
32
+ language: "en"
33
+ assets: ["statement/olymp.sty", "statement/*.png"]
33
34
  configure:
34
- - type: 'rbx-tex' # Convert rbxTeX to TeX
35
- template: 'statement/template.rbx.tex'
35
+ - type: "rbx-tex" # Convert rbxTeX to TeX
36
+ template: "statement/template.rbx.tex"
36
37
  stresses:
37
- - name: 'stress'
38
+ - name: "stress"
38
39
  generator:
39
- name: 'gen'
40
- args: '[1..<MAX_N>] @' # `@` generates a random string
41
- finder: '[sols/wa.cpp] ~ INCORRECT'
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 # Can be used in the validator, in stress tests and in the statement.
55
+ "MAX_N": 1000000000 # Can be used in the validator, in stress tests and in the statement.
44
56
 
@@ -1,2 +1,4 @@
1
1
  gen 123456
2
- gen 12345678
2
+ gen 12345678
3
+ # Obtained by running `rbx stress -g 'gen [1..<MAX_N>] @' -f '[sols/wa.cpp] ~ INCORRECT'`
4
+ gen 149403982 b139a2bd