On Feb 22, 2009, at 5:15 PM, Martin v. Löwis wrote:
What is the objective of this code? Is it a complete sandbox?
If not, is a complete sandbox based on it available somehow for
review?
From a cursory look at Tav's CPython patch, I'd describe it as follows:
Requires: an existing Python code execution environment
which does not expose unsafe interpreter
functionality to the (untrusted) code it runs,
Provides: a way for the trusted code outside of that
restricted environment to wrap functions
(which may reference trusted objects) in
closures which can be passed into the restricted
environment as completely opaque objects
whose internal state (including any referenced
trusted objects) cannot be accessed from the
untrusted code.
When I say 'requires', I mean 'requires to be useful'; the patch can
be applied to vanilla CPython, but isn't useful on its own.
Building blocks for a restricted execution environment as required by
the patch are commonly provided in templating libraries; Tav mentions
Genshi in particular. By default, Genshi templates don't come with
security built in -- you can do what you please in a template.
However, since Genshi manually constructs a Python AST from Python
code in the template, one can restrict the AST and modify the builtins
exposed to the template environment, making things like filesystem
access, import and other sensitive system facilities unavailable.
Even with those unavailable, untrusted code can break out of
containment by accessing object.__subclasses__ or gaining access to
gi_frame and gi_code. This means you can't, for instance, pass into
the untrusted code a closure which operates on trusted objects. Tav's
patch addresses this particular problem.
To give you a complete sandbox to play with, I just violently ripped
out the relevant code from Genshi, added some glue, and slapped it all
together in a single file along with Tav's pure-Python code which is
functionally equivalent to the CPython patch he submitted. The result,
tested on 2.5.1 and nothing else:
<http://radian.org/~krstic/sandbox.py>
As is, sandbox allows you to execute untrusted Python code which won't
have access to import, __import__, eval, exec, execfile, open, and to
which you can pass closures which reference trusted objects which the
untrusted code can't get at.
Example:
>>> import sandbox
>>> import sys
>>> import md5
>>> def trusted_pwd_closure(password):
... def get_pwd():
... return md5.md5(password).hexdigest()
... return get_pwd
...
>>> context = dict(pwd=trusted_pwd_closure('secret'))
>>> sandbox.run_string("print pwd()", context)
>>> sandbox.run_string("print pwd.func_closure[0].cell_contents",
context)
[snip]
AttributeError: 'function' object has no attribute 'func_closure'
Without Tav's patch, the untrusted code can extract our password
('secret') from the closure with that last statement.
To run whole files in the sandbox:
>>> sandbox.run_file('/some/path/file.py')
Finally, disclaimer: I put this together in *15 minutes*. I'm sure I
missed something, this isn't secure, etc. It's just a proof of
concept. Void where prohibited, etc.
Cheers,
--
Ivan Krstić <krs...@solarsail.hcs.harvard.edu> | http://radian.org
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com