Commit 8a9af1fd authored by Tres Seaver's avatar Tres Seaver

Branch for fixes for Collector #1460.

parent 9fbf32c0
...@@ -155,16 +155,43 @@ else: ...@@ -155,16 +155,43 @@ else:
# See comment in SimpleObjectPolicies for an explanation of what the # See comment in SimpleObjectPolicies for an explanation of what the
# dicts below actually mean. # dicts below actually mean.
ContainerAssertions[type({})] = { _dict_white_list = {
'clear':1, 'copy':1, 'fromkeys':1, 'get':get_dict_get, 'has_key':1, 'clear':1, 'copy':1, 'fromkeys':1, 'get':get_dict_get, 'has_key':1,
'items':1, 'iteritems':1, 'keys':1, 'items':1, 'iteritems':1, 'keys':1,
'iterkeys': get_iter, 'itervalues':get_iter, 'iterkeys': get_iter, 'itervalues':get_iter,
'pop':get_dict_pop, 'popitem':1, 'setdefault':1, 'update':1, 'values':1} 'pop':get_dict_pop, 'popitem':1, 'setdefault':1, 'update':1, 'values':1}
ContainerAssertions[type([])] = { def _check_dict_access(name, value):
# Check whether value is a dict method
self = getattr(value, '__self__', None)
if self is None: # item
return 1
# Disallow spoofing
if type(self) is not dict:
return 0
if getattr(value, '__name__', None) != name:
return 0
return _dict_white_list.get(name, 0)
ContainerAssertions[type({})] = _check_dict_access
_list_white_list = {
'append':1, 'count':1, 'extend':1, 'index':1, 'insert':1, 'append':1, 'count':1, 'extend':1, 'index':1, 'insert':1,
'pop':get_list_pop, 'remove':1, 'reverse':1, 'sort':1} 'pop':get_list_pop, 'remove':1, 'reverse':1, 'sort':1}
def _check_list_access(name, value):
# Check whether value is a dict method
self = getattr(value, '__self__', None)
if self is None: # item
return 1
# Disallow spoofing
if type(self) is not list:
return 0
if getattr(value, '__name__', None) != name:
return 0
return _list_white_list.get(name, 0)
ContainerAssertions[type([])] = _check_list_access
# This implementation of a "safe" iterator uses a global guard() # This implementation of a "safe" iterator uses a global guard()
# function to implement the actual guard. This check is defined as a # function to implement the actual guard. This check is defined as a
......
...@@ -404,16 +404,38 @@ class TestActualPython(GuardTestCase): ...@@ -404,16 +404,38 @@ class TestActualPython(GuardTestCase):
untouched.sort() untouched.sort()
self.fail("Unexercised wrappers: %r" % untouched) self.fail("Unexercised wrappers: %r" % untouched)
# Compile code in fname, as restricted Python. Return the def test_dict_access(self):
# compiled code, and a safe globals dict for running it in. from RestrictedPython.tests import verify
# fname is the string name of a Python file; it must be found
# in the same directory as this file. SIMPLE_DICT_ACCESS_SCRIPT = """
def _compile(self, fname): def foo(text):
return text
kw = {'text':'baz'}
print foo(**kw)
kw = {'text':True}
print foo(**kw)
"""
code, its_globals = self._compile_str(SIMPLE_DICT_ACCESS_SCRIPT, 'x')
verify.verify(code)
sm = SecurityManager()
old = self.setSecurityManager(sm)
import pdb; pdb.set_trace()
try:
exec code in its_globals
finally:
self.setSecurityManager(old)
self.assertEqual(its_globals['_print'](),
'baz\nTrue\n')
def _compile_str(self, text, name):
from RestrictedPython import compile_restricted from RestrictedPython import compile_restricted
from AccessControl.ZopeGuards import get_safe_globals, guarded_getattr from AccessControl.ZopeGuards import get_safe_globals, guarded_getattr
fn = os.path.join( _HERE, fname) code = compile_restricted(text, name, 'exec')
code = compile_restricted(open(fn).read(), fn, 'exec')
g = get_safe_globals() g = get_safe_globals()
g['_getattr_'] = guarded_getattr g['_getattr_'] = guarded_getattr
...@@ -421,6 +443,18 @@ class TestActualPython(GuardTestCase): ...@@ -421,6 +443,18 @@ class TestActualPython(GuardTestCase):
g['__name__'] = __name__ # so classes can be defined in the script g['__name__'] = __name__ # so classes can be defined in the script
return code, g return code, g
# Compile code in fname, as restricted Python. Return the
# compiled code, and a safe globals dict for running it in.
# fname is the string name of a Python file; it must be found
# in the same directory as this file.
def _compile(self, fname):
from RestrictedPython import compile_restricted
from AccessControl.ZopeGuards import get_safe_globals, guarded_getattr
fn = os.path.join( _HERE, fname)
text = open(fn).read()
return self._compile_str(text, fn)
# d is a dict, the globals for execution or our safe builtins. # d is a dict, the globals for execution or our safe builtins.
# The callable values which aren't the same as the corresponding # The callable values which aren't the same as the corresponding
# entries in __builtin__ are wrapped in a FuncWrapper, so we can # entries in __builtin__ are wrapped in a FuncWrapper, so we can
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment