24 September 2003

So right away I have something to show anyone who wants to look. I’ve been thinking about the whole RExec/Bastion problem, and I may have come up with a solution. I’d also certainly appreciate it if anyone could fill me in with any obvious security flaws

Check out SaferPython. It is my attempt to rewrite a restricted environment for Python. Admittedly, I don’t think I know enough about the new language features to be sure if this works. I’ve tried a number of “exploits”, and this seems to provide the kind of protection I want, but I’m pretty sure it doesn’t have the abilities that some RExec users need.

I wrote this based upon the following premises:

  • That my primary goal is to offer some sort of scripting enviroment, even if it is only a subset of the Python language. Call it PythonScript or something (ah, jk, I think that already exists)…
  • That any class/object that I could want in the restricted environment would be accessible to me ahead of time.
  • That none of the objects in this environment can return anything but safe objects

For the moment, I can be sure the the classes are secure, since importing is disabled from inside the environment. Only classes/objects that are imported explicitly are available.

The way you’d use it would be something like this:

from safer import *
import string

# defaults to using the NameChecker class for permissions
env = Armory()
# we insert objects that we want to access, including any modules
# or built-in functions
env.insert('string', string) #the string module
env.insert('str', str)       #the str() built-in/type

# we can also specify other IPermission implementations
class myClass(object):
    pass
env.insert('MyClass', MyClass, ClassProtection)

env.r_exec(someUntrustedCode)

The manual insertion of ALL language objects is a bit of a pain, but this can be automated once I figure out what classes/objects are 100% safe for this environment. Although there is support for creating new instances of protected (Shielded) class objects, they are currently returned unrestricted. I’m planning on fixing this once I figure out a nice way to do it.