• No results found

Building and breaking a Python sandbox

N/A
N/A
Protected

Academic year: 2021

Share "Building and breaking a Python sandbox"

Copied!
82
0
0

Loading.... (view fulltext now)

Full text

(1)

Building and breaking a

Python sandbox

(2)

Director

Organizer

@jessicamckellar

http://jesstess.com

(3)

Why?

Learning a language

Providing a hosted scratch pad

Distributed computation

(4)

Examples in the wild

Seattle’s peer-to-peer computing network

Google App Engine’s Python shell

Codecademy’s empythoned

(5)
(6)

Building a sandbox

Language-level sandboxing (

pysandbox

)

(7)

Question: How do we

execute arbitrary code?

(8)

How do we execute

arbitrary code?

exec

: compiles and evaluates

statements

>>> exec "print 'Hello world'"

Hello world

eval

: compiles and evaluates

expressions

>>> eval("1 + 2")

3

(9)

class

Sandbox

(object):

def

execute(

self

, code_string):

exec

code_string

(10)

from

sandbox

import

Sandbox

s = Sandbox()

code =

"""

print "Hello world!"

"""

s.execute(code)

(11)

$ python test_sandbox.py

Hello world!

from

sandbox

import

Sandbox

s = Sandbox()

code =

"""

print "Hello world!"

"""

(12)
(13)

What should we disallow?

Resource exhaustion

Information disclosure

Running unexpected services

Disabling/quitting/erroring out of the

(14)

from

sandbox

import

Sandbox

s

= Sandbox()

code

=

"""

file("test.txt", "w").write("Kaboom!\\n")

"""

s.execute(code)

(15)

>>> __builtins__.__dict__.keys()

['bytearray', 'IndexError', 'all', 'help', 'vars', 'SyntaxError', 'unicode',

'UnicodeDecodeError', 'memoryview', 'isinstance', 'copyright', 'NameError',

'BytesWarning', 'dict', 'input', 'oct', 'bin', 'SystemExit', 'StandardError', 'format', 'repr',

'sorted', 'False', 'RuntimeWarning', 'list', 'iter', 'reload', 'Warning', '__package__',

'round', 'dir', 'cmp', 'set', 'bytes', 'reduce', 'intern', 'issubclass', 'Ellipsis', 'EOFError',

'locals', 'BufferError', 'slice', 'FloatingPointError', 'sum', 'getattr', 'abs', 'exit', 'print',

'True', 'FutureWarning', 'ImportWarning', 'None', 'hash', 'ReferenceError', 'len',

'credits', 'frozenset', '__name__', 'ord', 'super', '_', 'TypeError', 'license',

'KeyboardInterrupt', 'UserWarning', 'filter', 'range', 'staticmethod', 'SystemError',

'BaseException', 'pow', 'RuntimeError', 'float', 'MemoryError', 'StopIteration',

'globals', 'divmod', 'enumerate', 'apply', 'LookupError', 'open', 'quit', 'basestring',

'UnicodeError', 'zip', 'hex', 'long', 'next', 'ImportError', 'chr', 'xrange', 'type', '__doc__',

'Exception', 'tuple', 'UnicodeTranslateError', 'reversed', 'UnicodeEncodeError',

'IOError', 'hasattr', 'delattr', 'setattr', 'raw_input', 'SyntaxWarning', 'compile',

'ArithmeticError', 'str', 'property', 'GeneratorExit', 'int', '__import__', 'KeyError',

'coerce', 'PendingDeprecationWarning', 'file', 'EnvironmentError', 'unichr', 'id',

'OSError', 'DeprecationWarning', 'min', 'UnicodeWarning', 'execfile', 'any', 'complex',

'bool', 'ValueError', 'NotImplemented', 'map', 'buffer', 'max', 'object', 'TabError',

'callable', 'ZeroDivisionError', 'eval', '__debug__', 'IndentationError',

'AssertionError', 'classmethod', 'UnboundLocalError', 'NotImplementedError',

'AttributeError', 'OverflowError']

(16)

>>> __builtins__.__dict__.keys()

['bytearray', 'IndexError', 'all', 'help', 'vars', 'SyntaxError', 'unicode',

'UnicodeDecodeError', 'memoryview', 'isinstance', 'copyright', 'NameError',

'BytesWarning', 'dict', 'input', 'oct', 'bin', 'SystemExit', 'StandardError', 'format', 'repr',

'sorted', 'False', 'RuntimeWarning', 'list', 'iter', 'reload', 'Warning', '__package__',

'round', 'dir', 'cmp', 'set', 'bytes', 'reduce', 'intern', 'issubclass', 'Ellipsis', 'EOFError',

'locals', 'BufferError', 'slice', 'FloatingPointError', 'sum', 'getattr', 'abs', 'exit', 'print',

'True', 'FutureWarning', 'ImportWarning', 'None', 'hash', 'ReferenceError', 'len',

'credits', 'frozenset', '__name__', 'ord', 'super', '_', 'TypeError', 'license',

'KeyboardInterrupt', 'UserWarning', 'filter', 'range', 'staticmethod', 'SystemError',

'BaseException', 'pow', 'RuntimeError', 'float', 'MemoryError', 'StopIteration',

'globals', 'divmod', 'enumerate', 'apply', 'LookupError', 'open', 'quit', 'basestring',

'UnicodeError', 'zip', 'hex', 'long', 'next', 'ImportError', 'chr', 'xrange', 'type', '__doc__',

'Exception', 'tuple', 'UnicodeTranslateError', 'reversed', 'UnicodeEncodeError',

'IOError', 'hasattr', 'delattr', 'setattr', 'raw_input', 'SyntaxWarning', 'compile',

'ArithmeticError', 'str', 'property', 'GeneratorExit', 'int', '__import__', 'KeyError',

'coerce', 'PendingDeprecationWarning', 'file', 'EnvironmentError', 'unichr', 'id',

'OSError', 'DeprecationWarning', 'min', 'UnicodeWarning', 'execfile', 'any', 'complex',

'bool', 'ValueError', 'NotImplemented', 'map', 'buffer', 'max', 'object', 'TabError',

'callable', 'ZeroDivisionError', 'eval', '__debug__', 'IndentationError',

'AssertionError', 'classmethod', 'UnboundLocalError', 'NotImplementedError',

'AttributeError', 'OverflowError']

(17)

How do we disallow

execution of

(18)
(19)

class

Sandbox

(object):

def execute(self, code_string):

keyword_blacklist

= [

"file"

,

"open"

,

"eval"

,

"exec"

]

for keyword in keyword_blacklist:

if keyword in code_string:

raise ValueError(

"Blacklisted"

)

exec code_string

(20)

from

sandbox

import

Sandbox

s

= Sandbox()

code

=

"""

file("test.txt", "w").write("Kaboom!\\n")

"""

s.execute(code)

(21)

from

sandbox

import

Sandbox

s

= Sandbox()

code

=

"""

file("test.txt", "w").write("Kaboom!\\n")

"""

s.execute(code)

$ python test_sandbox.py

Traceback (most recent call last):

File "test_sandbox.py", line 11, in

<module>

s.execute(code)

File "/Users/jesstess/Desktop/sandbox/

sandbox.py", line 86, in execute

raise ValueError("Blacklisted")

ValueError: Blacklisted

(22)

How can we get

around a keyword

(23)

Circumvention idea:

encryption

func

= __builtins__[

"file"

]

(24)

Circumvention idea:

encryption

func

= __builtins__[

"file"

]

func(

"test.txt"

,

"w"

).write(

"Kaboom!\n"

)

func

= __builtins__[

"svyr"

.decode(

"rot13"

)]

func(

"test.txt"

,

"w"

).write(

"Kaboom!\n"

)

(25)

from

sandbox

import

Sandbox

s

= Sandbox()

code

=

"""

func = __builtins__["svyr".decode("rot13")]

func("test.txt", "w").write("Kaboom!\\n")

"""

s.execute(code)

Testing: keyword blacklist

(26)

Observation: if I can get a

reference to something

(27)

How can we remove all

references to

(28)
(29)

builtins_whitelist

= set((

# exceptions

'ArithmeticError', 'AssertionError', 'AttributeError',

...

# constants

'False', 'None', 'True',

...

# types

'basestring', 'bytearray', 'bytes', 'complex', 'dict',

...

# functions

'__import__', 'abs', 'all', 'any', 'apply', 'bin', 'bool',

...

# block: eval, execfile, file, quit, exit, reload, etc.

(30)

import

sys

main

= sys.modules[

"__main__"

].__dict__

orig_builtins

= main[

"__builtins__

"].__dict__

builtins_whitelist

= set(( ... ))

for

builtin

in

orig_builtins.keys():

if

builtin

not in

builtins_whitelist:

del

orig_builtins[builtin]

(31)

from

sandbox

import

Sandbox

s

= Sandbox()

code

=

"""

file("test.txt", "w").write("Kaboom!\\n")

"""

s.execute(code)

(32)

from

sandbox

import

Sandbox

s

= Sandbox()

code

=

"""

file("test.txt", "w").write("Kaboom!\\n")

"""

s.execute(code)

$ python test_sandbox.py

Traceback (most recent call last):

File "test_sandbox.py", line 9, in

<module>

s.execute(code)

...

File "<string>", line 2, in <module>

NameError: name 'file' is not defined

(33)

Circumvention idea:

import something

(34)

from sandbox import Sandbox

s

= Sandbox()

code

=

"""

import os

fd = os.open("test.txt", os.O_CREAT|os.O_WRONLY)

os.write(fd, "Kaboom!\\n")

"""

s.execute(code)

Testing: builtins whitelist

(35)

How do we disallow

problematic imports?

(36)
(37)

>>>

importer

= __builtins__.__dict__.get(

"__import__"

)

>>>

os

= importer(

"os"

)

>>> os

<module 'os' from '/Library/Frameworks/

Python.framework/Versions/2.7/lib/python2.7/os.pyc'>

>>> os.getcwd()

'/Users/jesstess/Desktop/sandbox'

Idea: import whitelist

(38)

>>> help(__builtins__.__dict__[

"__import__"]

)

__import__(...)

__import__(name, globals={}, locals={},

fromlist=[], level=-1) -> module

Idea: import whitelist

What is the expected function signature for the

importer?

(39)

>>>

def

my_importer(module_name, globals={},

... locals={}, fromlist=[],

... level=-1):

...

print

"Using my importer!"

...

return

__import__(module_name, globals,

... locals, fromlist, level)

...

>>> os = my_importer(

"os"

)

Using my importer!

>>> os.getcwd()

'/Users/jesstess/Desktop/sandbox'

Idea: import whitelist

(40)

def

_safe_import(__import__, module_whitelist):

def

safe_import(module_name, globals={},

locals={}, fromlist=[],

level=-1):

!

if

module_name

in

module_whitelist:

return

__import__(module_name,

! ! ! ! ! ! ! ! ! ! ! !

globals, locals,

fromlist, level)

else

:

raise

ImportError(

"Blocked import of %s"

(

module_name,))

return

safe_import

(41)

import

sys

main

= sys.modules["__main__"].__dict__

orig_builtins

= main["__builtins__"].__dict__

for

builtin

in

orig_builtins.keys():

if

builtin

not in

builtins_whitelist:

del

original_builtins[builtin]

safe_modules

= [

"string"

,

"re"

]

orig_builtins[

"__import__"

] = _safe_import(

__import__, safe_modules)

(42)

from sandbox import Sandbox

s

= Sandbox()

code

=

"""

import os

fd = os.open("test.txt", os.O_CREAT|os.O_WRONLY)

os.write(fd, "Kaboom!\\n")

"""

s.execute(code)

(43)

from sandbox import Sandbox

s

= Sandbox()

code

=

"""

import os

fd = os.open("test.txt", os.O_CREAT|os.O_WRONLY)

os.write(fd, "Kaboom!\\n")

"""

s.execute(code)

Testing: import whitelist

$ python test_sandbox.py

Traceback (most recent call last):

File "test_sandbox.py", line 11, in

<module>

...

raise ImportError("Blocked import of

%s" % (module_name,))

(44)

Circumvention idea:

modifying builtins

(45)

Idea: make

builtins

(46)

How can we make an

object read-only in

(47)

class

ReadOnlyBuiltins

(dict):

def

__delitem__(

self

, key):

ValueError(

"Read-only!"

)

def

pop(

self

, key, default=None):

ValueError(

"Read-only!"

)

def

popitem(

self

):

ValueError(

"Read-only!"

)

...

def

setdefault(

self

, key, value):

ValueError(

"Read-only!"

)

def

__setitem__(

self

, key, value):

ValueError(

"Read-only!"

)

def

update(

self

, dict, **kw):

(48)

main

= sys.modules["__main__"].__dict__

orig_builtins

= main["__builtins__"].__dict__

for

builtin

in

orig_builtins.keys():

if

builtin

not in

builtins_whitelist:

del

original_builtins[builtin]

safe_modules

= [

"string"

,

"re"

]

orig_builtins[

"__import__"

] = _safe_import(

__import__, safe_modules)

safe_builtins

= ReadOnlyBuiltins(

original_builtins)

(49)

Observation redux: if I

can get a reference to

something bad, I can

invoke it.

(50)

Circumvention idea:

exploiting the

(51)

>>> dir([])

[

'__add__'

,

'__class__'

,

'__contains__'

,

'__delattr__'

,

'__delitem__'

,

'__delslice__'

,

'__doc__'

,

'__eq__'

,

'__format__'

,

'__ge__'

, ...]

>>> [].__class__

<type 'list'>

(52)

>>> [].__class__

<type 'list'>

>>> [].__class__.__bases__

(<type 'object'>,)

>>> [].__class__.__bases__[0]

<type 'object'>

What can we find out about an object’s base classes?

list

subclasses

(53)

>>> [].__class__.__subclasses__()

[]

>>> int.__subclasses__()

[<type 'bool'>]

>>> basestring.__subclasses__()

[<type 'str'>, <type 'unicode'>]

What can we find out about an object’s subclasses?

(54)

>>> [].__class__.__bases__

(<type 'object'>,)

>>> [].__class__.__bases__[0]

<type 'object'>

>>> [].__class__.__bases__[0].__subclasses__()

[<type 'type'>, <type 'weakref'>, <type 'weakcallableproxy'>, <type 'weakproxy'>, <type 'int'>, <type 'basestring'>, <type 'bytearray'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedType'>, <type 'traceback'>, <type 'super'>, <type 'xrange'>, <type 'dict'>, <type 'set'>, <type 'slice'>, <type

'staticmethod'>, <type 'complex'>, <type 'float'>, <type 'buffer'>, <type 'long'>, <type 'frozenset'>, <type 'property'>, <type 'memoryview'>, <type 'tuple'>, <type 'enumerate'>, <type 'reversed'>, <type

'code'>, <type 'frame'>, <type 'builtin_function_or_method'>, <type 'instancemethod'>, <type 'function'>, <type 'classobj'>, <type 'dictproxy'>, <type 'generator'>, <type 'getset_descriptor'>, <type

'wrapper_descriptor'>, <type 'instance'>, <type 'ellipsis'>, <type 'member_descriptor'>, <type 'file'>, <type 'PyCapsule'>, <type 'cell'>, <type 'callable-iterator'>, <type 'iterator'>, <type 'sys.long_info'>, <type 'sys.float_info'>, <type 'EncodingMap'>, <type 'fieldnameiterator'>, <type 'formatteriterator'>, <type 'sys.version_info'>, <type 'sys.flags'>, <type 'exceptions.BaseException'>, <type 'module'>, <type 'imp.NullImporter'>, <type 'zipimport.zipimporter'>, <type 'posix.stat_result'>, <type

'posix.statvfs_result'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class '_abcoll.Hashable'>, <type

'classmethod'>, <class '_abcoll.Iterable'>, <class '_abcoll.Sized'>, <class '_abcoll.Container'>, <class '_abcoll.Callable'>, <class 'site._Printer'>, <class 'site._Helper'>, <type '_sre.SRE_Pattern'>, <type

'_sre.SRE_Match'>, <type '_sre.SRE_Scanner'>, <class 'site.Quitter'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'string.Template'>, <class 'string.Formatter'>, <type

'operator.itemgetter'>, <type 'operator.attrgetter'>, <type 'operator.methodcaller'>, <type 'collections.deque'>, <type 'deque_iterator'>, <type 'deque_reverse_iterator'>, <type

'itertools.combinations'>, <type 'itertools.combinations_with_replacement'>, <type 'itertools.cycle'>, <type 'itertools.dropwhile'>, <type 'itertools.takewhile'>, <type 'itertools.islice'>, <type

'itertools.starmap'>, <type 'itertools.imap'>, <type 'itertools.chain'>, <type 'itertools.compress'>, <type 'itertools.ifilter'>, <type 'itertools.ifilterfalse'>, <type 'itertools.count'>, <type 'itertools.izip'>, <type 'itertools.izip_longest'>, <type 'itertools.permutations'>, <type 'itertools.product'>, <type

'itertools.repeat'>, <type 'itertools.groupby'>, <type 'itertools.tee_dataobject'>, <type 'itertools.tee'>, <type 'itertools._grouper'>, <type '_thread._localdummy'>, <type 'thread._local'>, <type 'thread.lock'>, <class 'sandbox.Protection'>, <type 'resource.struct_rusage'>, <class 'sandbox.config.SandboxConfig'>, <class 'sandbox.proxy.ReadOnlySequence'>, <class 'sandbox.sandbox_class.Sandbox'>, <class

'sandbox.restorable_dict.RestorableDict'>]

All of the subclasses

of

object!

(55)

>>> [].__class__.__bases__

(<type 'object'>,)

>>> [].__class__.__bases__[0]

<type 'object'>

>>>

obj_class

= [].__class__.__bases__[0]

>>>

for

c

in

obj_class.__subclasses__():

...

print

c.__name__

...

wrapper_descriptor

instance

ellipsis

member_descriptor

file

PyCapsule

cell

callable-iterator

iterator

...

(56)

>>> [].__class__.__bases__

(<type 'object'>,)

>>> [].__class__.__bases__[0]

<type 'object'>

>>> obj_class = [].__class__.__bases__[0]

>>> for c in obj_class.__subclasses__():

... print c.__name__

...

wrapper_descriptor

instance

ellipsis

member_descriptor

file

PyCapsule

cell

callable-iterator

iterator

...

!!!

(57)

from sandbox import Sandbox

s

= Sandbox()

code

=

"""

obj_class = [].__class__.__bases__[0]

obj_subclasses = dict((elt.__name__, elt) for \

elt in obj_class.__subclasses__())

func = obj_subclasses["file"]

func("text.txt", "w").write("Kaboom!\\n")

"""

s.execute(code)

Testing: read-only builtins

(58)

Idea: don’t expose

dangerous

(59)

>>> type.__bases__

(<type 'object'>,)

>>>

del

type.__bases__

(60)

>>> type.__bases__

(<type 'object'>,)

>>> del type.__bases__

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

TypeError: can't set attributes of

built-in/extension type 'type'

Let’s delete

__bases__

and

__subclasses__

Imposed by the underlying

C implementation!

(61)

from ctypes import pythonapi, POINTER, py_object

_get_dict

= pythonapi._PyObject_GetDictPtr

_get_dict.restype = POINTER(py_object)

_get_dict.argtypes = [py_object]

del pythonapi, POINTER, py_object

def dictionary_of(ob):

dptr

= _get_dict(ob)

return dptr.contents.value

cpython.py

(62)

from

cpython

import

dictionary_of

main

= sys.modules[

"__main__"

].__dict__

...

safe_builtins

= ReadOnlyBuiltins(

original_builtins)

main[

"__builtins__"

] = safe_builtins

type_dict

= dictionary_of(type)

del

type_dict[

"__bases__"

]

(63)

Circumvention idea:

would a function by any

other name smell as

(64)

>>>

def

foo():

...

print

"Meow"

...

>>> dir(foo)

[

'__call__'

,

'__class__'

,

'__closure__'

,

'__code__'

,

'__defaults__'

,

'__delattr__'

,

'__dict__'

,

'__doc__'

,

'__format__'

,

'__get__'

,

'__getattribute__'

,

'__globals__'

,

'__hash__'

,

'__init__'

,

'__module__'

,

'__name__'

,

'__new__'

,

'__reduce__'

,

'__reduce_ex__'

,

'__repr__'

,

'__setattr__'

,

'__sizeof__'

,

'__str__'

,

'__subclasshook__'

,

'func_closure'

,

'func_code'

,

'func_defaults'

,

'func_dict'

,

'func_doc'

,

(65)

>>>

def

foo():

...

print

"Meow"

...

>>> dir(foo)

[

'__call__'

,

'__class__'

,

'__closure__'

,

'__code__'

,

'__defaults__'

,

'__delattr__'

,

'__dict__'

,

'__doc__'

,

'__format__'

,

'__get__'

,

'__getattribute__'

,

'__globals__'

,

'__hash__'

,

'__init__'

,

'__module__'

,

'__name__'

,

'__new__'

,

'__reduce__'

,

'__reduce_ex__'

,

'__repr__'

,

'__setattr__'

,

'__sizeof__'

,

'__str__'

,

'__subclasshook__'

,

'func_closure'

,

'func_code'

,

'func_defaults'

,

'func_dict'

,

'func_doc'

,

'func_globals'

,

'func_name'

]

(66)

>>> foo.func_code

<code object foo at 0x100509d30, file "<stdin>",

line 1>

>>> dir(foo.func_code)

[

'__class__', '__cmp__', '__delattr__', '__doc__',

'__eq__', '__format__', '__ge__',

'__getattribute__', '__gt__', '__hash__',

'__init__', '__le__', '__lt__', '__ne__',

'__new__', '__reduce__', '__reduce_ex__',

'__repr__', '__setattr__', '__sizeof__',

'__str__', '__subclasshook__', 'co_argcount',

'co_cellvars', 'co_code', 'co_consts',

'co_filename', 'co_firstlineno', 'co_flags',

'co_freevars', 'co_lnotab', 'co_name', 'co_names',

'co_nlocals', 'co_stacksize', 'co_varnames'

]

>>> foo.func_code.co_code

'd\x01\x00GHd\x00\x00S'

(67)

>>>

def

foo():

...

print

"Meow"

...

>>>

def

evil_function():

...

print

"Kaboom!"

...

>>> foo()

Meow

>>> foo.__setattr__(

"func_code"

,

evil_function.func_code)

>>> foo()

Kaboom!

Kaboom

(68)

Idea redux: don’t

expose dangerous

(69)

from

cpython

import

dictionary_of

from

types

import

FunctionType

...

type_dict

= dictionary_of(type)

del

type_dict[

"__bases__"

]

del

type_dict[

"__subclasses__"

]

function_dict

= dictionary_of(FunctionType)

del

function_dict[

"func_code"

]

(70)

Whew. Let’s recap tactics:

Keyword blacklist

Builtins whitelist

Import whitelist

Making important objects read-only (builtins)

Deleting problematic implementation details

(

__bases__

,

__subclasses__,

func_code

)

Deleting the ability to construct arbitrary

(71)

We have run out of

tricks!

We’ve implemented 80% of a full-fledged

Python sandbox

(72)

builtins_whitelist = set((

# exceptions 'ArithmeticError', 'AssertionError', 'AttributeError', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'EnvironmentError', 'Exception', 'FloatingPointError','FutureWarning', 'GeneratorExit', 'IOError', 'ImportError',

'ImportWarning', 'IndentationError', 'IndexError', 'KeyError','LookupError', 'MemoryError', 'NameError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError','PendingDeprecationWarning', 'ReferenceError', 'RuntimeError',

'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'TabError', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError','UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', # constants

'False', 'None', 'True', '__doc__', '__name__', '__package__', 'copyright', 'license', 'credits',

# types

'basestring', 'bytearray', 'bytes', 'complex', 'dict', 'float', 'frozenset', 'int', 'list', 'long', 'object', 'set', 'str', 'tuple', 'unicode',

# functions '__import__', 'abs', 'all', 'any', 'apply', 'bin', 'bool', 'buffer', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'delattr', 'dir', 'divmod', 'enumerate', 'filter', 'format', 'getattr', 'globals', 'hasattr', 'hash', 'hex', 'id', 'isinstance', 'issubclass', 'iter', 'len', 'locals', 'map', 'max', 'min', 'next', 'oct', 'ord', 'pow', 'print', 'property', 'range', 'reduce', 'repr', 'reversed', 'round', 'setattr', 'slice', 'sorted', 'staticmethod', 'sum', 'super', 'type', 'unichr', 'vars', 'xrange', 'zip',

))

def _safe_import(__import__, module_whitelist):

def safe_import(module_name, globals={}, locals={}, fromlist=[], level=-1): if module_name in module_whitelist:

return __import__(module_name, globals, locals, fromlist, level) else:

raise ImportError("Blocked import of %s" % (module_name,)) return safe_import

class ReadOnlyBuiltins(dict): def clear(self):

ValueError("Read-only!") def __delitem__(self, key): ValueError("Read-only!") def pop(self, key, default=None): ValueError("Read-only!") def popitem(self):

ValueError("Read-only!") def setdefault(self, key, value):

! ValueError("Read-only!") def __setitem__(self, key, value): ValueError("Read-only!") def update(self, dict, **kw): ValueError("Read-only!")

class Sandbox(object): def __init__(self): ! import sys

! from types import FunctionType

! from cpython import dictionary_of

! original_builtins = sys.modules["__main__"].__dict__["__builtins__"].__dict__

! for builtin in original_builtins.keys(): if builtin not in builtins_whitelist:

! ! del sys.modules["__main__"].__dict__["__builtins__"].__dict__[builtin]

original_builtins["__import__"] = _safe_import(__import__, ["string", "re"])

safe_builtins = ReadOnlyBuiltins(original_builtins) sys.modules["__main__"].__dict__["__builtins__"] = safe_builtins ! type_dict = dictionary_of(type) ! del type_dict["__bases__"] ! del type_dict["__subclasses__"] ! function_dict = dictionary_of(FunctionType) ! del function_dict["func_code"]

def execute(self, code_string): ! exec code_string

builtins whitelist

import whitelist

read-only builtins

deleting

__bases__

,

__subclasses_

,

and

func_code

(73)

Building a sandbox

Language-level sandboxing (

pysandbox

)

(74)

What should we disallow?

Resource exhaustion

Information disclosure

Running unexpected services

Disabling/quitting/erroring out of the

(75)
(76)

Is this level of

reflectiveness

good

(77)

Do

other languages

have these sandboxing

(78)

If you were designing a

new language

, how

(79)

Experiments

How does an alternative Python implementation

like

PyPy

handle these issues?

How does the CPython interpreter compile and

run

bytecode

?

What does the Python

stack

look like?

How do

ctypes

work?

How can the

operating system

help provide a

(80)

Bedtime reading

The full

pysandbox

implementation:

https://github.com/haypo/pysandbox/

A retrospective on

pysandbox’s challenges

:

https://lwn.net/Articles/574215/

PyPy’s sandbox

implementation:

http://pypy.readthedocs.org/en/latest/sandbox.html

How

PythonAnywhere

’s sandbox works:

http://blog.pythonanywhere.com/83/

(81)
(82)

Let’s talk!

O’Reilly booth, 3pm

References

Related documents

• reverse (bool) – whether the iterator should iterate in reverse order • start (bytes) – the start key (inclusive by default) of the iterator range • stop (bytes) – the stop

The forget items received no retrieval practice opportunities in any of the retrieval practice schedules, but might be expected to undergo greater forgetting in the maximize

Early iterations were related to training data selection, activation functions, and what type of neural network should be used: MLP, LSTM, GRU, or CNN.. The

This paper discusses the development of several Economic Model Predictive Control (EMPC) based strategies for solving an energy dispatch problem in a smart micro-grid.. The smart

Since Set interface or HashSet class doesn't provide will get method to retrieve elements the gift way your take out elements from schedule Set group to iterate over population by

The java iterator, implement serializable interface adds them need of implementing efficient traversal of linked list collection to iterate through elements using.. This

Returns Iterator which yields all pages of this sitemap and linked sitemaps (if

bool priority queue:: empty () const ; C ontainer::size type. priority queue:: size () const