/sandbox/attributes.py

https://bitbucket.org/yingted/pysandbox
Python | 84 lines | 55 code | 9 blank | 20 comment | 10 complexity | e672f5ae70585ade32eea6234a4a3b84 MD5 | raw file
  1. from __future__ import absolute_import
  2. from types import FunctionType, FrameType, GeneratorType
  3. from sys import version_info
  4. from sandbox import Protection
  5. try:
  6. from sys import _clear_type_cache
  7. except ImportError:
  8. # Python < 2.6 has no type cache, so we don't have to clear it
  9. def _clear_type_cache():
  10. pass
  11. from .cpython import dictionary_of
  12. from .restorable_dict import RestorableDict
  13. builtin_function = type(len)
  14. class HideAttributes(Protection):
  15. """
  16. Hide unsafe frame attributes from the Python space
  17. """
  18. def __init__(self):
  19. self.dict_dict = RestorableDict(dictionary_of(dict))
  20. self.function_dict = RestorableDict(dictionary_of(FunctionType))
  21. self.frame_dict = RestorableDict(dictionary_of(FrameType))
  22. self.type_dict = RestorableDict(dictionary_of(type))
  23. self.builtin_func_dict = RestorableDict(dictionary_of(builtin_function))
  24. self.generator_dict = RestorableDict(dictionary_of(GeneratorType))
  25. def enable(self, sandbox):
  26. if not sandbox.config.cpython_restricted:
  27. # Deny access to func.func_code to avoid an attacker to modify a
  28. # trusted function: replace the code of the function
  29. hide_func_code = True
  30. else:
  31. # CPython restricted mode already denies read and write access to
  32. # function attributes
  33. hide_func_code = False
  34. # Blacklist all dict methods able to modify a dict, to protect
  35. # ReadOnlyBuiltins
  36. for name in (
  37. '__init__', 'clear', '__delitem__', 'pop', 'popitem',
  38. 'setdefault', '__setitem__', 'update'):
  39. del self.dict_dict[name]
  40. if version_info < (3, 0):
  41. # pysandbox stores trusted objects in closures: deny access to
  42. # closures to not leak these secrets
  43. del self.function_dict['func_closure']
  44. del self.function_dict['func_globals']
  45. if hide_func_code:
  46. del self.function_dict['func_code']
  47. del self.function_dict['func_defaults']
  48. if version_info >= (2, 6):
  49. del self.function_dict['__closure__']
  50. del self.function_dict['__globals__']
  51. if hide_func_code:
  52. del self.function_dict['__code__']
  53. del self.function_dict['__defaults__']
  54. del self.frame_dict['f_locals']
  55. # Hiding type.__bases__ crashs CPython 2.5 because of a infinite loop
  56. # in PyErr_ExceptionMatches(): it calls abstract_get_bases() but
  57. # abstract_get_bases() fails and call PyErr_ExceptionMatches() ...
  58. if version_info >= (2, 6):
  59. # Setting __bases__ crash Python < 3.3a2
  60. # http://bugs.python.org/issue14199
  61. del self.type_dict['__bases__']
  62. # object.__subclasses__ leaks the file type in Python 2
  63. # and (indirectly) the FileIO file in Python 3
  64. del self.type_dict['__subclasses__']
  65. del self.builtin_func_dict['__self__']
  66. _clear_type_cache()
  67. def disable(self, sandbox):
  68. self.dict_dict.restore()
  69. self.function_dict.restore()
  70. self.frame_dict.restore()
  71. self.type_dict.restore()
  72. self.builtin_func_dict.restore()
  73. self.generator_dict.restore()
  74. # Python 2.6+ uses a method cache: clear it to avoid errors
  75. _clear_type_cache()