def test_clone(self): s = Sandbox(self.task[2]) s.policy = MinimalPolicy() s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RF) pass
def test_open(self): s = Sandbox(self.task[0]) s.policy = SelectiveOpenPolicy(s, set([(b"/dev/zero", O_RDONLY), ])) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_OK) pass
def run_user_code(language, code, stdin): error, error_msg, output = False, None, None sandbox = None try: if language not in LANG_CONFIG: raise UnsupportedLanguage(f'{language} is not supported') sandbox = Sandbox() sandbox.run(language, code, stdin) except Exception as e: error = True error_msg = f'[{e.__class__.__name__}] {e}' try: if not error: with open(sandbox.output_file_path, 'r') as f: output = f.read() else: output = '' except Exception as e: output = '' rv = { 'error': error, 'error_msg': error_msg, 'output': output, 'exec_time': sandbox.execution_time if sandbox else -1, } return rv
def test_open(self): s = Sandbox(self.task[0]) s.policy = SelectiveOpenPolicy(s, set([ (b"/dev/zero", O_RDONLY), ])) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_OK) pass
def test_sigtrap_user(self): s = Sandbox(self.task[4]) s.policy = KillerPolicy(s, SIGTRAP) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RT) d = s.probe(False) self.assertEqual(d['signal_info'], (SIGTRAP, SI_USER)) pass
def test_rlimit_cpu(self): s = Sandbox(self.task[6]) s.policy = AllowResLimitPolicy(s) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RT) d = s.probe(False) self.assertEqual(d['signal_info'], (SIGXCPU, SI_KERNEL)) pass
def test_ol_file_write(self): s = Sandbox(self.task[0], quota=dict(wallclock=60000, cpu=2000, disk=5)) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_OL) with open(self.fout[0], "rb") as f: self.assertEqual(f.read(), b"Hello") f.close() pass
def test_sigkill(self): s = Sandbox(self.task[4]) s.policy = KillerPolicy(s, SIGKILL) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RT) d = s.probe(False) self.assertEqual(d['signal_info'][0], SIGKILL) pass
def test_sigsegv_accerr(self): s = Sandbox(self.task[3]) s.policy = MinimalPolicy() s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RT) d = s.probe(False) self.assertEqual(d['signal_info'], (SIGSEGV, SEGV_ACCERR)) pass
def test_sigfpe_intdiv(self): s = Sandbox(self.task[1]) s.policy = MinimalPolicy() s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RT) d = s.probe(False) self.assertEqual(d['signal_info'], (SIGFPE, FPE_INTDIV)) pass
def test_sigbus_adraln(self): s = Sandbox(self.task[0]) s.policy = MinimalPolicy() s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RT) d = s.probe(False) self.assertEqual(d['signal_info'], (SIGBUS, BUS_ADRALN)) pass
def test_int80_fork(self): # syscall #2: (fork, i686) vs (open, x86_64) s = Sandbox(self.task[1]) s.policy = MinimalPolicy() s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RF) d = s.probe(False) self.assertEqual(d['syscall_info'], (2, 1)) pass
def test_ml_static(self): s = Sandbox(self.task[0], quota=dict(wallclock=60000, cpu=2000, memory=2 ** 24)) s.policy = MinimalPolicy() s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_ML) d = s.probe(False) mem = d['mem_info'][1] * 1024 self.assertLess(s.quota[Sandbox.S_QUOTA_MEMORY], mem) pass
def test_kill_ppid(self): s = Sandbox(self.task[0]) s.policy = AllowSelfKillPolicy(s) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RF) d = s.probe(False) sc = d['syscall_info'] if machine() == 'x86_64' else d['syscall_info'][0] self.assertTrue(sc in AllowSelfKillPolicy.SC_kill) pass
def test_rlimit_fsz(self): s_wr = open(config.touch("rlimit_fsz.out"), "wb") s = Sandbox(self.task[5], stdout=s_wr) s.policy = AllowResLimitPolicy(s) s.run() s_wr.close() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_OL) d = s.probe(False) self.assertEqual(d['signal_info'], (SIGXFSZ, SI_USER)) pass
def test_open_bogus(self): # dumping bad address should cause RT not BP/IE s = Sandbox(self.task[2]) s.policy = SelectiveOpenPolicy(s, set()) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RT) d = s.probe(False) sc = d['syscall_info'] if machine() == 'x86_64' else d['syscall_info'][0] self.assertTrue(sc in SelectiveOpenPolicy.SC_open) pass
def test_exec_nested(self): # nested execve(): ./exec.exe ./exec.exe ./hello.exe s = Sandbox([self.task[0], ] + self.task[:]) s.policy = AllowExecOncePolicy() s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RF) d = s.probe(False) sc = d['syscall_info'] if machine() == 'x86_64' else d['syscall_info'][0] self.assertTrue(sc in AllowExecOncePolicy.SC_execve) pass
def test_int80_exit1(self): # syscall #1: (exit, i686) vs (write, x86_64) s = Sandbox(self.task[0]) s.policy = AllowExitPolicy() s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_AT) d = s.probe(False) self.assertEqual(d['exitcode'], 1) self.assertEqual(d['syscall_info'], (1, 1)) pass
def test_exec_rf(self): # minimal policy forbids execve() s = Sandbox(self.task[:]) s.policy = MinimalPolicy() s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RF) d = s.probe(False) sc = d['syscall_info'] if machine() == 'x86_64' else d['syscall_info'][0] self.assertTrue(sc in AllowExecOncePolicy.SC_execve) pass
def test_ol_redirected(self): s_wr = open(self.fout[1], "wb") s = Sandbox(self.task[1], quota=dict(wallclock=60000, cpu=2000, disk=5), stdout=s_wr) s.run() s_wr.close() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_OL) with open(self.fout[1], "rb") as f: self.assertEqual(f.read(), b"Hello") f.close() pass
def test_sigkill_io(self): s_rd, s_wr = os.pipe() s = Sandbox(self.task[7], stdin=s_rd) s.policy = KillerPolicy(s, SIGKILL) s.run() os.fdopen(s_rd, "rb").close() os.fdopen(s_wr, "wb").close() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RT) d = s.probe(False) self.assertEqual(d['signal_info'][0], SIGKILL) pass
def test_tl_busy_loop_1s(self): s = Sandbox(self.task[0], quota=dict(wallclock=60000, cpu=1000)) s.policy = MinimalPolicy() s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_TL) d = s.probe(False) cpu = d['cpu_info'][0] eps = config.MAX_CPU_OVERRUN self.assertLess(s.quota[Sandbox.S_QUOTA_CPU], cpu) self.assertLess(cpu - s.quota[Sandbox.S_QUOTA_CPU], eps) pass
def test_open_bogus(self): # dumping bad address should cause RT not BP/IE s = Sandbox(self.task[2]) s.policy = SelectiveOpenPolicy(s, set()) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RT) d = s.probe(False) sc = d['syscall_info'] if machine( ) == 'x86_64' else d['syscall_info'][0] self.assertTrue(sc in SelectiveOpenPolicy.SC_open) pass
def test_tl_sleep(self): s = Sandbox(self.task[3], quota=dict(wallclock=1000, cpu=2000)) s.policy = AllowPauseSleepPolicy(s) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_TL) d = s.probe(False) elapsed = d['elapsed'] eps = config.MAX_WALLCLOCK_OVERRUN self.assertLess(s.quota[Sandbox.S_QUOTA_WALLCLOCK], elapsed) self.assertLess(elapsed - s.quota[Sandbox.S_QUOTA_WALLCLOCK], eps) pass
def test_exec_rf(self): # minimal policy forbids execve() s = Sandbox(self.task[:]) s.policy = MinimalPolicy() s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RF) d = s.probe(False) sc = d['syscall_info'] if machine( ) == 'x86_64' else d['syscall_info'][0] self.assertTrue(sc in AllowExecOncePolicy.SC_execve) pass
def test_exec(self): # single execve(): ./exec.exe ./hello.exe s_rd, s_wr = os.pipe() s = Sandbox(self.task[:], stdout=s_wr) s.policy = AllowExecOncePolicy() s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_OK) os.fdopen(s_wr, 'wb').close() with os.fdopen(s_rd, 'rb') as f: self.assertEqual(f.read(), b"Hello World!\n") f.close() pass
def test_assert(self): s_wr = open("/dev/null", "wb") s = Sandbox(self.task[1], stderr=s_wr) s.policy = AllowSelfKillPolicy(s) s.run() s_wr.close() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RT) d = s.probe(False) self.assertEqual(d['signal_info'], (SIGABRT, SI_TKILL)) sc = d['syscall_info'] if machine() == 'x86_64' else d['syscall_info'][0] self.assertTrue(sc in AllowSelfKillPolicy.SC_tgkill) pass
def test_sigxfsz_user(self): s = Sandbox(self.task[4]) s.policy = KillerPolicy(s, SIGXFSZ) s.run() # this results in OL instead of RT because the way linux file systems # notify disk quota limitation is simply sending SIGXFSZ to the program # unfortunately the si_code is SI_USER making it not distinguishable # from a synthetic SIGXFSZ signal sent from third party self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_OL) d = s.probe(False) self.assertEqual(d['signal_info'], (SIGXFSZ, SI_USER)) pass
def test_assert_rf(self): s_wr = open("/dev/null", "wb") s = Sandbox(self.task[1], stderr=s_wr) s.policy = MinimalPolicy() s.run() s_wr.close() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RF) d = s.probe(False) sc = d['syscall_info'] if machine() == 'x86_64' else d['syscall_info'][0] self.assertTrue(sc in AllowSelfKillPolicy.SC_rt_sigprocmask or sc in AllowSelfKillPolicy.SC_sigprocmask) pass
def test_ml_alloc(self): s_wr = open("/dev/null", "wb") s = Sandbox(self.task[1], quota=dict(wallclock=60000, cpu=2000, memory=2 ** 24), stderr=s_wr) s.policy = MinimalPolicy() s.run() s_wr.close() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_ML) d = s.probe(False) mem = d['mem_info'][1] * 1024 self.assertLess(s.quota[Sandbox.S_QUOTA_MEMORY], mem) pass
def test_piped_stdout(self): # sbox /bin/echo "Hello World!" | /bin/cat s_rd, s_wr = os.pipe() s = Sandbox(["/bin/echo", "Hello", "World!"], stdout=s_wr) p = Popen("/bin/cat", close_fds=True, stdin=s_rd, stdout=PIPE) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_OK) # close the write-end of the pipe before reading from the read-end os.fdopen(s_wr, 'wb').close() os.fdopen(s_rd, 'rb').close() stdout, stderr = p.communicate() self.assertEqual(stdout, b"Hello World!\n") pass
def test_exit_group1(self): s = Sandbox(self.task[3]) s.policy = MinimalPolicy() s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_AT) # validate profiling d = s.probe(False) self.assertEqual(d['exitcode'], 1) cpu = d['cpu_info'][0] # cpu clock time mem = d['mem_info'][1] # peak vm size self.assertTrue(cpu >= 0) self.assertTrue(mem > 0) pass
def test_exec_nested(self): # nested execve(): ./exec.exe ./exec.exe ./hello.exe s = Sandbox([ self.task[0], ] + self.task[:]) s.policy = AllowExecOncePolicy() s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_RF) d = s.probe(False) sc = d['syscall_info'] if machine( ) == 'x86_64' else d['syscall_info'][0] self.assertTrue(sc in AllowExecOncePolicy.SC_execve) pass
def test_chroot_jail_ok(self): nobody = getpwnam('nobody') s = Sandbox(self.task[2], jail=self.prefix, owner=nobody.pw_uid, group=nobody.pw_gid) s.policy = SelectiveOpenPolicy(s, [(self.fout[2].encode(), O_WRONLY | O_CREAT | O_TRUNC), ]) self.assertEqual(s.jail, self.prefix) self.assertEqual(s.owner, nobody.pw_uid) self.assertEqual(s.group, nobody.pw_gid) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_OK) # make sure file content is not changed with open(os.path.join(self.prefix, self.fout[2]), "rb") as f: self.assertEqual(f.read(), b"Hello World!\n") f.close() pass
def test_hello_world(self): s_wr = open("/dev/null", "wb") s = Sandbox(self.task[0], stdout=s_wr) s.run() s_wr.close() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_OK) # validate profiling d = s.probe(False) self.assertEqual(d['exitcode'], 0) cpu = d['cpu_info'][0] # cpu clock time mem = d['mem_info'][1] # peak vm size self.assertTrue(cpu >= 0) self.assertTrue(mem > 0) pass
def test_tl_blocking_io(self): s_rd, s_wr = os.pipe() s = Sandbox(self.task[1], quota=dict(wallclock=1000, cpu=2000), stdin=s_rd) s.policy = MinimalPolicy() s.run() os.fdopen(s_rd, "rb").close() os.fdopen(s_wr, "wb").close() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_TL) d = s.probe(False) elapsed = d['elapsed'] eps = config.MAX_WALLCLOCK_OVERRUN self.assertLess(s.quota[Sandbox.S_QUOTA_WALLCLOCK], elapsed) self.assertLess(elapsed - s.quota[Sandbox.S_QUOTA_WALLCLOCK], eps) pass
def test_owner_group(self): nobody = getpwnam('nobody') s = Sandbox(self.task[0], owner=nobody.pw_uid, group=nobody.pw_gid) s.policy = SelectiveOpenPolicy(s, [(self.fout[0].encode(), O_WRONLY | O_CREAT | O_TRUNC), ]) self.assertEqual(s.owner, nobody.pw_uid) self.assertEqual(s.group, nobody.pw_gid) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_AT) d = s.probe(False) self.assertEqual(d['exitcode'], EACCES) # make sure file content is not changed with open(self.fout[0], "rb") as f: self.assertEqual(f.read(), self.secret) f.close() pass
def compile_code(language, code, stdin): temp_folder = os.path.join('/tmp', str(uuid.uuid4())) timeout_value = 20 path = os.getcwd() sandbox = Sandbox(timeout_value=timeout_value, path=path, temp_folder=temp_folder, compiler_name=compiler_dict[language][0], file_name=compiler_dict[language][1], code=code, output_command=compiler_dict[language][2], language_name=compiler_dict[language][3], e_arguments=compiler_dict[language][4], stdin_data=stdin) (data, exec_time, err) = sandbox.run() return { "output": data, "langid": language, "code": code, "errors": err, "time": exec_time }
def test_piped_stdin(self): # /bin/echo "Hello World" | sbox /bin/cat p_rd, p_wr = os.pipe() p = Popen(["/bin/echo", "Hello", "World!"], close_fds=True, stdout=p_wr) os.fdopen(p_wr, 'wb').close() s_rd, s_wr = os.pipe() s = Sandbox("/bin/cat", stdin=p_rd, stdout=s_wr) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_OK) # close the write-end of the pipe before reading from the read-end os.fdopen(s_wr, 'wb').close() with os.fdopen(s_rd, 'rb') as f: self.assertEqual(f.read(), b"Hello World!\n") f.close() pass
def test_a_plus_b(self): p_rd, p_wr = os.pipe() p = Popen(["/bin/echo", "1", "2"], close_fds=True, stdout=p_wr) os.fdopen(p_wr, 'wb').close() s_rd, s_wr = os.pipe() s = Sandbox(self.task[1], stdin=p_rd, stdout=s_wr) s.run() self.assertEqual(s.status, Sandbox.S_STATUS_FIN) self.assertEqual(s.result, Sandbox.S_RESULT_OK) # validate result os.fdopen(s_wr, 'wb').close() with os.fdopen(s_rd, 'rb') as f: self.assertEqual(f.read(), b"3\n") f.close() # validate profiling d = s.probe(False) cpu = d['cpu_info'][0] # cpu clock time mem = d['mem_info'][1] # peak vm size self.assertTrue(cpu >= 0) self.assertTrue(mem > 0) pass
def compile(self): # compile must be done in 20 seconds s = Sandbox( time_limit=20000, # 20s mem_limit=1048576, # 1GB image=self.image[self.lang], src_dir=f'{self.working_dir}/{self.submission_id}/src', lang_id=self.lang_id[self.lang], compile_need=1) result = s.run() if result['Status'] == 'Exited Normally': result['Status'] = 'AC' elif result['Status'] != 'JE': result['Status'] = 'CE' return result
def run(self): s = Sandbox(time_limit=self.time_limit, mem_limit=self.mem_limit, image=self.image[self.lang], src_dir=f'{self.working_dir}/{self.submission_id}/src', lang_id=self.lang_id[self.lang], compile_need=0, stdin_path=self.testdata_input_path) result = s.run() # Status Process with open(self.testdata_output_path, 'r') as f: ans_output = f.read() status = {'TLE', 'MLE', 'RE', 'OLE', 'JE'} if not result['Status'] in status: result['Status'] = 'WA' res_outs = self.strip(result['Stdout']) ans_outputs = self.strip(ans_output) if res_outs == ans_outputs: result['Status'] = 'AC' return result
from sandbox import Sandbox code = ''' object Hello { def main(args: Array[String]) = { println("hello world") } } ''' s = Sandbox(time_limit=10) print(s.run('scala', code))
from sandbox import Sandbox code = ''' #include <iostream> int main() { std::cout << "start from cpp" << std::endl; for(int i = 0; i < 10; ++i) { std::cout << i << " " << i * i << std::endl; } std::cout << "end" << std::endl; } ''' s = Sandbox() print(s.run('cpp', code))
from sandbox import Sandbox code = ''' fn main() { println!("Hello World from rust!!"); } ''' s = Sandbox() print(s.run('rust', code))
def start_player(data): return Sandbox.run(data[0], data[1])