summaryrefslogtreecommitdiff
path: root/python/runner/interpreter.py
blob: da60d72c7584bf23f3536815e66568b5f4bfee61 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/python3 -u

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('<run>\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 ValueError:
                break
            except EOFError:
                break

    def runcode(self, code):
        try:
            exec(code, self.locals)
        except KeyboardInterrupt:
            self.write('^C')
            raise
        except SystemExit as ex:
            raise
        except:
            # Show traceback for all other exceptions.
            self.showtraceback()

MyConsole().interact()