sandboxing python code

Michael Chermside mcherm at mcherm.com
Tue Jun 3 13:54:59 EDT 2003


Ben writes about executing untrusted code:

> 1. Have a pseudo language which I then can render doen to python before
> running. But then whats the point of using python? I want to give them all
> the power of python where allowed

If your pseudo-language is turing complete, then it's still possible
for users to write things like infinite loops that you can't tell
are infinite (that's the whole point of the "haulting problem"). So
you can't solve the untrusted code problem with this approach.

> 2. Simply run the code using exec with restricted globals and locals
> dictionaries. This can stop people importing dodgy libraries, but cannot
> stop people writing infinite loops etc

As noted, doesn't really fix it.

> 3. Use the parser to generate the AST for the program, and then add checks
> inside for loops etc which will cause the program to quit if a certain
> counter reaches a maximum. This doesn't solve the memory problem either.

Doesn't prevent it from running forever either. That can be done in
a single line within python, quite easily. Try, for instance, executing
this:
   x = 1000000000 ** 10000

> 4. Use the c api to run the compiled bytecode a batch at a time, e.g run
> for a 100 instructions and the check a condition, bailing out if it fails.
> This still doesn't stop people doing something like range(100000000), and
> also doesn't seem to have support in the api, so would entail effectively
> writing my own python virtual machine.

Not really much better. You still haven't gotten at the root cause -- you
can't TELL whether some code is going to use more resources than you
intended, so there's no way to trap this and stop the offending code.

What to do? Well, what you need is a large and complex system for
managing resources. It should be responsible for providing nearly all
resources -- timeslicing CPU use, allocating memory, mitigating access
to disk, network sockets, etc, etc. Such a system is called an
"operating system".

Okay, forgive me my dramatic phrasing... the truth is that resource
restriction is best done by the operating system... and, in fact, pretty
much can ONLY be done by the operating system (if you built something
to manage resources this well, you'd be creating your own OS). So the
REAL solution is to use the OS.

Take this untrusted code and run it in a separate process. Run that
process with limits on its memory and CPU consumption, or continually
monitor the process and kill it if its memory and CPU use get out of
hand. Really, this is pretty much the ONLY solution that can truly work
(and some operating systems aren't capable of this kind of protection...
if yours isn't, I recommend an upgrade). Anything less, and you're just
fooling yourself (there are lots of ways to protect against ACCIDENTALLY
incorrect code, but if you are facing actual malicious code, then only
the OS can help).

There are some problems with this approach. For one thing, the overhead
can be quite significant. If you're running little 5-line python
snippets, launching a whole python interpreter each time, and setting
up pipes or files to communicate between processes requires a huge
amount of overhead. If you REALLY care about this, you could write a
system that launches a separate Python process which talks over a socket
to the initiating process and accepts bits of python code to run and
returns the results. A separate thread would monitor this separate
process and kill it if it starts misbehaving. The currently running
code snippet(s) would fail, but then a new "watched process" could be
launched. Such a tool would, I think, be superficially very popular. 
Very popular because reliable sandboxing of untrusted code is a frequent
request in this newsgroup, and superficially because I suspect that *in
reality* serious programmers (as opposed to armchair speculators) rarely
need to execute untrusted code (as evidenced by the lack of an existing
library doing this). The only difficult part would be cross-OS
portability.

-- Michael Chermside








More information about the Python-list mailing list