Hi guys! I know this subject has been beaten to death and I am not going to whine about lacking features for proper restricted execution in the Python runtime. It's the OS job, I get it.
Anyways, I thought about using a restricted *subset* of the language for simple configuration scripts and storing data in a user-friendly way. I'm fully aware about the dangers of introducing "eval" into the picture so I took different route and hacked together the following module: http://www.zafar.se/dump/safe.py Could some of you perhaps give some feedback on the implementation? By default the module imposes the following restrictions: * importing modules is disabled * unsafe builtins are disabled * timeout limit ('while 1:pass' can't block forever) * getattr, setattr, delattr are disabled * lowlevel attributes like __subclasses__ are disabled * enviroment passed to 'exec' can't contain modules or builtins Is there some obvious security hole I'm missing? How easily could one compromise the restricted enviroment? Thanks, Babar K. Zafar PS. Here are some simple unittests to give you a feel for the module: class TestSafeEval(unittest.TestCase): def test_builtin(self): # attempt to access a unsafe builtin self.assertRaises(SafeEvalException, safe_eval, "open('test.txt', 'w')") def test_getattr(self): # attempt to get arround direct attr access self.assertRaises(SafeEvalException, \ safe_eval, "getattr(int, '__abs__')") def test_func_globals(self): # attempt to access global enviroment where fun was defined self.assertRaises(SafeEvalException, \ safe_eval, "def x(): pass; print x.func_globals") def test_lowlevel(self): # lowlevel tricks to access 'object' self.assertRaises(SafeEvalException, \ safe_eval, "().__class__.mro()[1].__subclasses__()") def test_timeout_ok(self): # attempt to exectute slow code which finishes within timelimit def test(): time.sleep(2) env = {'test':test} safe_eval("test()", env, timeout_secs = 5) def test_timeout_exceed(self): # attempt to exectute code which never teminates self.assertRaises(SafeEvalException, \ safe_eval, "while 1: pass") def test_invalid_context(self): # can't pass an enviroment with modules or builtins env = {'f' : __builtins__.open, 'g' : time} self.assertRaises(SafeEvalException, \ safe_eval, "print 1", env) def test_callback(self): # modify local variable via callback self.value = 0 def test(): self.value = 1 env = {'test':test} safe_eval("test()", env) self.assertEqual(self.value, 1) -- http://mail.python.org/mailman/listinfo/python-list