def test_builtins_object_is_readonly(self): # If __builtins__ is accessible, it should be read-only, so # that it can be shared between mutually distrusting modules, # and so that __import__ cannot be assigned (because it # exposes the "locals" dict). # We don't make the __builtins__ object accessible though. # This test uses a trick of passing in "globals", which is not # a safe function, so that we can test an object that is not # normally accessible. code = 'globals()["__builtins__"]["__import__"] = 1' env = safeeval.Environment() env.bind("globals", globals) try: safeeval.safe_eval(code, env) except TypeError, exn: self.assertEquals(str(exn), "'module' object does not support item assignment")
def test_default_module_attributes(self): env = safeeval.Environment() module = safeeval.safe_eval("", env) # Checks that Python is not adding extra attributes to the # module or to its __builtins__ object. self.assertEquals(sorted(module.__dict__.keys()), ["__builtins__", "__doc__", "__name__"]) self.assertEquals(sorted(env._module.__dict__.keys()), ["__doc__", "__name__"])
def test_informative_error(self): try: safeeval.safe_eval( """ def func(): x.y = 1 """, safeeval.Environment(), ) except safeeval.VerifyError, exn: self.assertEquals( str(exn), """ line 3: SetAttr, in func x.y = 1\ """, )
def test_assignment_to_global(self): module = safeeval.safe_eval( """ global a a = 42 """, safeeval.Environment(), ) self.assertEquals(visible_dict(module.__dict__), {"a": 42})
def test_import_wrapping(self): # Check that the import function is not passed locals or # globals dictionaries. class Example(object): baz = 1 bazz = 2 got = [] def my_import(*args): got.append(args) return Example() env = safeeval.Environment() env.set_importer(my_import) safeeval.safe_eval( """ import foo.bar1 from foo.bar2 import baz as quux, bazz as quuux """, env, ) self.assertEquals(got, [("foo.bar1", None), ("foo.bar2", ("baz", "bazz"))])
def exploit(): captured = [] def my_import(name, globals, locals, fromlist): captured.append(locals["method"]) safeeval.safe_eval( """ class C: def method(self): self._private = "dangerous" import bob """, {"__import__": my_import}, ) self.assertEquals(len(captured), 1) class UnrelatedObject(object): pass obj = UnrelatedObject() captured[0](obj) self.assertEquals(obj._private, "dangerous1")
def test_initial_environment(self): env = safeeval.Environment() env.bind("x", 123) env_copy = dict(env._module.__dict__) module = safeeval.safe_eval( """ y = x x = 456 """, env, ) # The __builtins__ dictionary should be unchanged despite the # assignment to "x". self.assertEquals(env._module.x, 123) self.assertEquals(env._module.__dict__, env_copy) self.assertEquals(visible_dict(module.__dict__), {"y": 123, "x": 456})
def test_safesuper_oldstyle(self): code = """ class C: def _method(self, arg): return "foo%i" % arg def f(self): return self._method(1) class D(C): def _method(self, arg): return safesuper(self, C, "_method")(arg + 1) + "bar" x = D().f() """ m = safeeval.safe_eval(code, safeeval.safe_environment()) self.assertEquals(m.x, "foo2bar")
def test_rejecting_bad_code(self): self.assertRaises(safeeval.VerifyError, lambda: safeeval.safe_eval("x._y", safeeval.Environment()))
def test_no_access_to_builtins(self): self.assertRaises(NameError, lambda: safeeval.safe_eval("open", safeeval.Environment()))
def test_assignment_to_local(self): module = safeeval.safe_eval("a = 42", safeeval.Environment()) self.assertEquals(visible_dict(module.__dict__), {"a": 42})
def test_import_failing(self): try: safeeval.safe_eval("import foo", safeeval.Environment()) except ImportError, exn: self.assertEquals(str(exn), "__import__ not found")