Closed eswxxxa closed 3 years ago
eswxxxa wrote at 2021-6-8 19:16 -0700:
i am learning restrictedPython, and i found open() can't be restricted if it is used in a function the below is my test code: a.py: from RestrictedPython import compile_restricted from RestrictedPython.Guards import safe_builtins _globals = dict(builtins=safe_builtins)
with open("/flash/b.py", 'r') as f: src = f.read() byte_code = compile_restricted(src, '/flash/liu.py', 'exec') exec (byte_code, _globals, {}) b.py: open("/flash/c.py", 'w')
test output is normal: Traceback (most recent call last): File "/flash/a.py", line 8, in
exec (byte_code, _globals, {}) File "/flash/b.py", line 1, in open("/flash/c.py", 'w') NameError: name 'open' is not defined then i modify the b.py: def heal_test(): open("/flash/hua.py", 'w')
the test result can pass.
The restriction happens when the function is called (not when it is defined).
RestrictedPython
controls access to builtins (such as open
)
via safe_builtins
. When a function is defined names are not
accessed but only classified as either global, local or non-local.
The actual access happens when the function is called -- and
then it will be detected that open
is not in safe_builtins
.
hi d-maurer, thanks for your clarification. i called this function in another file without restrictedPython, i used a.py to ensure the b.py
eswxxxa wrote at 2021-6-8 19:16 -0700: i am learning restrictedPython, and i found open() can't be restricted if it is used in a function the below is my test code: a.py: from RestrictedPython import compile_restricted from RestrictedPython.Guards import safe_builtins _globals = dict(builtins=safe_builtins) with open("/flash/b.py", 'r') as f: src = f.read() byte_code = compile_restricted(src, '/flash/liu.py', 'exec') exec (byte_code, _globals, {}) b.py: open("/flash/c.py", 'w') test output is normal: Traceback (most recent call last): File "/flash/a.py", line 8, in
exec (byte_code, _globals, {}) File "/flash/b.py", line 1, in open("/flash/c.py", 'w') NameError: name 'open' is not defined then i modify the b.py: def heal_test(): open("/flash/hua.py", 'w') the test result can pass. The restriction happens when the function is called (not when it is defined). RestrictedPython
controls access to builtins (such asopen
) viasafe_builtins
. When a function is defined names are not accessed but only classified as either global, local or non-local. The actual access happens when the function is called -- and then it will be detected thatopen
is not insafe_builtins
.
thanks d-maurer for your clarification. the function is called in another file without restrictedPython, i used a.py to ensure the b.py don't include open(). if exist open(), the another file can not be executived. in this case, what should i do to ensure b.py don't include open()?
what should i do to ensure b.py don't include open()?
Why would you do this? Your test shows that it cannot be used in the RestrictedPython environment.
eswxxxa wrote at 2021-6-8 23:14 -0700:
hi d-maurer, thanks for your clarification. i called this function in another file without restrictedPython, i used a.py to ensure the b.py
This is not how RestrictedPython
works:
What globals (among them builtins
) are available to compiled
code (whether compiled "normally" or with RestrictedPython
)
is determined by the globals
parameter you pass to exec/eval
.
If you do not want open
to be usable, to not include it
in this dict nor its __builtins__
.
RestrictedPython
is essentially using a specialized compilation
which replaces some elementary Python operations (essentially attribute and
item access) by function calls such that they can be controlled
externally (by putting appropriate definitions for those functions
into the globals
parameter).
... what should i do to ensure b.py don't include open()?
RestrictedPython
by itself does not support this.
Of course, you can (in principle) derive your own version
of RestrictedPython
which does this.
RestrictedPython
uses an AST (= "Abstract Syntax Tree", i.e.
the abstract representation of a piece of Python code)
transformation to modify the code such that its execution can
(to some extent) by controlled externally.
You could start with this transformation and add more restrictions
or control possibilities.
Note however, that the policy you implement should not be based on names (alone): the "open" functionality can easily be provided via a different name: you need a complete and carefull view on the whole context to develop a (quite) safe policy.
ok i know. thanks for your support.
when i call this function, i found open() is still available. i used the python version is 3.9.2, restrictedPython is 5.1
a.py: from RestrictedPython import compile_restricted from RestrictedPython.Guards import safe_builtins _globals = dict(builtins=safe_builtins)
with open("/flash/b.py", 'r') as f: src = f.read() byte_code = compile_restricted(src, '/flash/b.py', 'exec') exec (byte_code, _globals, {}) from b import heal_test heal_test()
b.py: def heal_test(): open("/flash/c.py", 'w')
eswxxxa wrote at 2021-6-30 00:37 -0700:
when i call this function, i found open() is still available.
Your observation is wrong: you do not call the restricted function but the unrestriced one. Details below.
i used the python version is 3.9.2, restrictedPython is 5.1
a.py: from RestrictedPython import compile_restricted from RestrictedPython.Guards import safe_builtins _globals = dict(builtins=safe_builtins)
with open("/flash/b.py", 'r') as f: src = f.read() byte_code = compile_restricted(src, '/flash/b.py', 'exec') exec (byte_code, _globals, {})
The restricted function would be found in the "locals" passed
down to the exec
.
from b import heal_test
This imports b
and compiles it - unrestricted!
From it, you get the unrestricted function heal_test
.
heal_test()
... and call it here.
eswxxxa wrote at 2021-6-30 00:37 -0700: when i call this function, i found open() is still available. Your observation is wrong: you do not call the restricted function but the unrestriced one. Details below. i used the python version is 3.9.2, restrictedPython is 5.1 a.py: from RestrictedPython import compile_restricted from RestrictedPython.Guards import safe_builtins _globals = dict(builtins=safe_builtins) with open("/flash/b.py", 'r') as f: src = f.read() byte_code = compile_restricted(src, '/flash/b.py', 'exec') exec (byte_code, _globals, {}) The restricted function would be found in the "locals" passed down to the
exec
. from b import heal_test This importsb
and compiles it - unrestricted! From it, you get the unrestricted functionheal_test
. heal_test() ... and call it here.
hi d-maurer, i modify the a.py, but the open() is still available. Could you give me a correct example? thanks very much a.py:
from RestrictedPython import compile_restricted
from RestrictedPython.Guards import safe_builtins
_builtins = dict(__builtins__=safe_builtins)
_builtins['__import__'] = __import__
_globals = globals()
_globals['__builtins__'] = _builtins
with open("/flash/b.py", 'r') as f:
src = f.read()
byte_code = compile_restricted(src, "/flash/b.py", 'exec')
exec (byte_code, _globals)
heal_test()
eswxxxa wrote at 2021-7-1 01:30 -0700:
hi d-maurer,
Try:
... with open("/flash/b.py", 'r') as f: src = f.read() byte_code = compile_restricted(src, "/flash/b.py", 'exec') locals = {} exec (byte_code, _globals, locals) locals["heal_test"]()
To successfully (and safely) use RestrictedPython
,
you must understand how Python works:
source code is compiled into byte code
Compilation usually happens automatically on the initial module import. The source code does not have an identity: if you compile the "same" code several times, you get several byte code sequences.
byte code is executed in an enviroment (given
by the globals
and loacals
parameters)
a function definition combines (previously compiled)
byte code with various pieces, among them globals
,
into a function object and "binds" it to the
function name in the current local namespace.
hi d-maurer, i used your code and the open() is still worked and the c.py is created bash-4.3# python3 a.py bash-4.3# bash-4.3# ls a.py b.py c.py bash-4.3#
eswxxxa wrote at 2021-7-1 02:52 -0700:
hi d-maurer, i used your code and the open() is still worked and the c.py is created
>>> from RestrictedPython import compile_restricted
>>> from RestrictedPython.Guards import safe_builtins
>>>
>>> G = globals().copy()
>>> G["__builtins__"] = safe_builtins
>>> src = "def f(): return open"
>>>
>>> code = compile_restricted(src, "<string>", "exec")
>>> L = {}
>>> exec(code, G, L)
>>> L["f"]()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in f
NameError: name 'open' is not defined
As it should be.
ok, d-maurer , thanks for your support.
i am learning restrictedPython, and i found open() can't be restricted if it is used in a function. i used the python version is 3.9.2 the below is my test code: a.py: from RestrictedPython import compile_restricted from RestrictedPython.Guards import safe_builtins _globals = dict(builtins=safe_builtins)
with open("/flash/b.py", 'r') as f: src = f.read() byte_code = compile_restricted(src, '/flash/b.py', 'exec') exec (byte_code, _globals, {}) b.py: open("/flash/c.py", 'w')
test output is normal: Traceback (most recent call last): File "/flash/a.py", line 8, in
exec (byte_code, _globals, {})
File "/flash/b.py", line 1, in
open("/flash/c.py", 'w')
NameError: name 'open' is not defined
then i modify the b.py: def heal_test(): open("/flash/c.py", 'w')
the test result can pass.
what should i do to restrict the open() if it is used in a function? thanks.