This repository has been archived by the owner on Aug 30, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 31
/
interpreter.py
158 lines (145 loc) · 5.21 KB
/
interpreter.py
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
from __future__ import with_statement
from code import InteractiveConsole
from sandbox import Sandbox, SandboxConfig, HAVE_PYPY
try:
import readline
except ImportError:
pass
from optparse import OptionParser
from sandbox.version import VERSION
import sys
from sys import version_info
def getEncoding():
encoding = sys.stdin.encoding
if encoding:
return encoding
# sys.stdin.encoding is None if stdin is not a tty
# Emulate PYTHONIOENCODING on Python < 2.6
import os
env = os.getenv('PYTHONIOENCODING')
if env:
return env.split(':',1)[0]
# Fallback to locales
import locale
return locale.getpreferredencoding()
ENCODING = getEncoding()
class SandboxConsole(InteractiveConsole):
# Backport Python 2.6 fix for input encoding
def raw_input(self, prompt):
line = InteractiveConsole.raw_input(self, prompt)
if not isinstance(line, unicode):
line = line.decode(ENCODING)
return line
class SandboxedInterpeter:
def __init__(self):
self.sandbox_locals = None
self.options = self.parseOptions()
self.config = self.createConfig()
self.stdout = sys.stdout
def parseOptions(self):
parser = OptionParser(usage="%prog [options]")
SandboxConfig.createOptparseOptions(parser, default_timeout=None)
parser.add_option("--debug",
help="Debug mode",
action="store_true", default=False)
parser.add_option("--verbose", "-v",
help="Verbose mode",
action="store_true", default=False)
parser.add_option("--quiet", "-q",
help="Quiet mode",
action="store_true", default=False)
options, argv = parser.parse_args()
if argv:
parser.print_help()
exit(1)
if options.quiet:
options.verbose = False
return options
def createConfig(self):
config = SandboxConfig.fromOptparseOptions(self.options)
config.enable('traceback')
config.enable('stdin')
config.enable('stdout')
config.enable('stderr')
config.enable('exit')
config.enable('site')
config.enable('encodings')
config._builtins_whitelist.add('compile')
config.allowModuleSourceCode('code')
config.allowModule('sys',
'api_version', 'version', 'hexversion')
config.allowSafeModule('sys', 'version_info')
if HAVE_PYPY:
config.enable('unicodedata')
config.allowModule('os', 'write', 'waitpid')
config.allowSafeModule('pyrepl', 'input')
config.allowModule('pyrepl.keymap', 'compile_keymap', 'parse_keys')
if self.options.debug:
config.allowModule('sys', '_getframe')
config.allowSafeModule('_sandbox', '_test_crash')
config.allowModuleSourceCode('sandbox')
if not config.cpython_restricted:
config.allowPath(__file__)
return config
def dumpConfig(self):
if self.options.debug:
from pprint import pprint
print "Sandbox config:"
pprint(self.config.__dict__)
else:
features = ', '.join(sorted(self.config.features))
print "Enabled features: %s" % features
if self.config.cpython_restricted:
print "CPython restricted mode enabled."
if self.config.use_subprocess:
text = "Run untrusted code in a subprocess"
if self.options.debug:
from os import getpid
text += ": pid=%s" % getpid()
print(text)
if 'help' not in self.config.features:
print "(use --features=help to enable the help function)"
print
def displayhook(self, result):
if result is None:
return
self.sandbox_locals['_'] = result
text = repr(result)
if not self.options.quiet:
print(text)
else:
self.stdout.write(text)
def interact(self):
console = SandboxConsole()
self.sandbox_locals = console.locals
if not self.options.quiet:
banner = "Try to break the sandbox!"
else:
banner = ''
console.interact(banner)
def main(self):
if not self.options.quiet:
print("pysandbox %s" % VERSION)
self.dumpConfig()
if 'help' in self.config.features:
# Import pydoc here because it uses a lot of modules
# blocked by the sandbox
import pydoc
if self.config.cpython_restricted:
# Import is blocked in restricted mode, so preload modules
import codecs
import encodings
import encodings.utf_8
import encodings.utf_16_be
if version_info >= (2, 6):
import encodings.utf_32_be
if sys.stdout.encoding:
codecs.lookup(sys.stdout.encoding)
codecs.lookup(ENCODING)
sys.ps1 = '\nsandbox>>> '
sys.ps2 = '.......... '
sys.displayhook = self.displayhook
sandbox = Sandbox(self.config)
sandbox.call(self.interact)
if __name__ == "__main__":
SandboxedInterpeter().main()