Permalink
Browse files

Limit input and output sizes

Use also the highest pickle protocol instead of the lowest protocol
  • Loading branch information...
vstinner committed Mar 21, 2012
1 parent 29d199a commit b8cb3a1d7537710f23181a5fc285ef448e52732e
Showing with 64 additions and 34 deletions.
  1. +1 −0 ChangeLog
  2. +1 −0 README
  3. +14 −0 sandbox/config.py
  4. +4 −2 sandbox/subprocess_child.py
  5. +44 −32 sandbox/subprocess_parent.py
View
@@ -11,6 +11,7 @@ Version 1.6
* stdin, stdout and stderr are redirected to /dev/null (or :NUL on Windows)
* Drop the "interpreter" configuration feature: move the code to interpreter.py
* Replace sys.path and other related variables
+ * Limit input and output sizes
Version 1.5 (2012-03-20)
------------------------
View
1 README
@@ -29,6 +29,7 @@ limits:
* number of child process = 0 (disable fork or thread at the OS level)
* pysandbox is able to catch crashes like segmentation fault (SIGSEGV)
* stdin, stdout and stderr are redirected to /dev/null (or :NUL on Windows)
+ * input and output data are limited to 64 KB
Protection of the namespace:
View
@@ -82,9 +82,15 @@ def __init__(self, *features, **kw):
if self._use_subprocess:
self._timeout = DEFAULT_TIMEOUT
self._max_memory = 50 * 1024 * 1024
+ # size in bytes of all input objects serialized by pickle
+ self._max_input_size = 64 * 1024
+ # size in bytes of the result serialized by pickle
+ self._max_output_size = 64 * 1024
else:
self._timeout = None
self._max_memory = None
+ self._max_input_size = None
+ self._max_output_size = None
# open() whitelist: see safe_open()
self._open_whitelist = set()
@@ -208,6 +214,14 @@ def _set_timeout(self, timeout):
def max_memory(self):
return self._max_memory
+ @property
+ def max_input_size(self):
+ return self._max_input_size
+
+ @property
+ def max_output_size(self):
+ return self._max_output_size
+
@property
def import_whitelist(self):
return dict((name, (tuple(value[0]), tuple(value[1])))
@@ -9,6 +9,8 @@
except ImportError:
resource = None
+PICKLE_PROTOCOL = pickle.HIGHEST_PROTOCOL
+
def set_process_limits(config):
if resource is not None:
# deny fork and thread
@@ -65,7 +67,7 @@ def execute_child():
output_data['locals'] = locals
except base_exception, err:
output_data = {'error': err}
- pickle.dump(output_data, output)
+ pickle.dump(output_data, output, PICKLE_PROTOCOL)
output.flush()
output.close()
@@ -78,7 +80,7 @@ def call_child(wpipe, sandbox, func, args, kw):
except BaseException, err:
data = {'error': err}
output = os.fdopen(wpipe, 'wb')
- pickle.dump(data, output)
+ pickle.dump(data, output, PICKLE_PROTOCOL)
output.flush()
output.close()
if config.has_feature("stdout"):
@@ -67,41 +67,53 @@ def execute_subprocess(sandbox, code, globals, locals):
finally:
os.umask(old_umask)
- with input_file:
- with output_file:
- input_data = {
- 'code': code,
- 'config': sandbox.config,
- 'locals': locals,
- 'globals': globals,
- }
- args = (
- sys.executable,
- # FIXME: use '-S'
- '-E',
- '-m', 'sandbox.subprocess_child',
- input_file.name, output_file.name)
- pickle.dump(input_data, input_file)
- # FIXME: check data size?
- input_file.flush()
+ try:
+ input_data = {
+ 'code': code,
+ 'config': sandbox.config,
+ 'locals': locals,
+ 'globals': globals,
+ }
+ args = (
+ sys.executable,
+ # FIXME: use '-S'
+ '-E',
+ '-m', 'sandbox.subprocess_child',
+ input_file.name, output_file.name)
+ pickle.dump(input_data, input_file)
+ input_file.flush()
+ if sandbox.config.max_input_size:
+ size = input_file.tell()
+ if size > sandbox.config.max_input_size:
+ raise SandboxError("Input data are too big: %s bytes (max=%s)"
+ % (size, sandbox.config.max_input_size))
- # create the subprocess
- process = subprocess.Popen(args, close_fds=True, shell=False)
+ # create the subprocess
+ process = subprocess.Popen(args, close_fds=True, shell=False)
- # wait data
- exitcode = process.wait()
- if exitcode:
- if os.name != "nt" and exitcode < 0:
- signum = -exitcode
- if signum == SIGALRM:
- raise Timeout()
- text = "subprocess killed by signal %s" % signum
- else:
- text = "subprocess failed with exit code %s" % exitcode
- raise SandboxError(text)
+ # wait data
+ exitcode = process.wait()
+ if exitcode:
+ if os.name != "nt" and exitcode < 0:
+ signum = -exitcode
+ if signum == SIGALRM:
+ raise Timeout()
+ text = "subprocess killed by signal %s" % signum
+ else:
+ text = "subprocess failed with exit code %s" % exitcode
+ raise SandboxError(text)
- output_data = pickle.load(output_file)
- # FIXME: check data size?
+ if sandbox.config.max_output_size:
+ output_file.seek(0, 2)
+ size = output_file.tell()
+ output_file.seek(0)
+ if size > sandbox.config.max_output_size:
+ raise SandboxError("Output data are too big: %s bytes (max=%s)"
+ % (size, sandbox.config.max_output_size))
+ output_data = pickle.load(output_file)
+ finally:
+ input_file.close()
+ output_file.close()
if 'error' in output_data:
raise output_data['error']

0 comments on commit b8cb3a1

Please sign in to comment.