From 76cbfe9d620ca66a374b828c011c937918f80c2c Mon Sep 17 00:00:00 2001 From: Timotej Lazar Date: Wed, 7 Oct 2015 17:25:35 +0200 Subject: Add a sandbox for Python interpreter Switch to user "nobody" and set additional limits. --- python/runner/interpreter.py | 87 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100755 python/runner/interpreter.py (limited to 'python/runner/interpreter.py') diff --git a/python/runner/interpreter.py b/python/runner/interpreter.py new file mode 100755 index 0000000..dae4d59 --- /dev/null +++ b/python/runner/interpreter.py @@ -0,0 +1,87 @@ +#!/usr/bin/python3 + +import code +import sys + +import seccomp + +f = seccomp.SyscallFilter(defaction=seccomp.KILL) +# Necessary for Python. +f.add_rule(seccomp.ALLOW, "brk") +f.add_rule(seccomp.ALLOW, "exit_group") +f.add_rule(seccomp.ALLOW, "ioctl") +f.add_rule(seccomp.ALLOW, "mmap") +f.add_rule(seccomp.ALLOW, "munmap") +f.add_rule(seccomp.ALLOW, "rt_sigaction") +f.add_rule(seccomp.ALLOW, "rt_sigreturn") + +# Mostly harmless. +f.add_rule(seccomp.ALLOW, "mprotect") + +# Allow reading from stdin and writing to stdout/stderr. +f.add_rule(seccomp.ALLOW, "read", seccomp.Arg(0, seccomp.EQ, sys.stdin.fileno())) +f.add_rule(seccomp.ALLOW, "write", seccomp.Arg(0, seccomp.EQ, sys.stdout.fileno())) +f.add_rule(seccomp.ALLOW, "write", seccomp.Arg(0, seccomp.EQ, sys.stderr.fileno())) + +# Needed for finding source code for exceptions. +f.add_rule(seccomp.ALLOW, "stat") +f.add_rule(seccomp.ALLOW, "open", seccomp.Arg(1, seccomp.MASKED_EQ, 0x3, 0)) # O_RDONLY +f.add_rule(seccomp.ALLOW, "close") +f.add_rule(seccomp.ALLOW, "read") +f.add_rule(seccomp.ALLOW, "fstat") +f.add_rule(seccomp.ALLOW, "lseek") +f.add_rule(seccomp.ALLOW, "fcntl") + +# Needed for help(). +f.add_rule(seccomp.ALLOW, "openat", seccomp.Arg(2, seccomp.MASKED_EQ, 0x3, 0)) # O_RDONLY +f.add_rule(seccomp.ALLOW, "getdents") +f.add_rule(seccomp.ALLOW, "getrlimit", seccomp.Arg(0, seccomp.EQ, 3)) # RLIMIT_STACK +f.add_rule(seccomp.ALLOW, "getrlimit", seccomp.Arg(0, seccomp.EQ, 7)) # RLIMIT_NOFILE + +# Needed for code.InteractiveConsole. +f.add_rule(seccomp.ALLOW, "access") +f.add_rule(seccomp.ALLOW, "select") +f.load() + +class MyConsole(code.InteractiveConsole): + def interact(self, banner=None): + if banner is not None: + self.write('{}\n'.format(banner)) + + buffer = [] + prompt = '>>> ' + while True: + try: + line = input(prompt) + # Assume we are running the user's program; silence the prompt. + if line == 'exec("""\\': + self.write('\n') + prompt = '' + + buffer.append(line) + source = '\n'.join(buffer) + more = self.runsource(source) + if more: + if prompt: + prompt = '... ' + else: + prompt = '>>> ' + buffer = [] + except KeyboardInterrupt: + prompt = '>>> ' + buffer = [] + self.write('\n') + except EOFError: + break + + def runcode(self, code): + try: + exec(code, self.locals) + except KeyboardInterrupt: + # Don't show traceback on SIGINT. + self.write('^C') + raise + except: + self.showtraceback() + +MyConsole().interact() -- cgit v1.2.1