Skip to content

Commit

Permalink
fix generator_escape
Browse files Browse the repository at this point in the history
  • Loading branch information
loechel committed Jul 6, 2023
1 parent 214fd35 commit ef41f33
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 24 deletions.
1 change: 1 addition & 0 deletions docs/contributing/index.rst
Expand Up @@ -64,6 +64,7 @@ To do so:
All AST Nodes without an explicit ``visit_<AST Node>`` method, are denied by default.
So the usage of this expression and functionality is not allowed.

* check the documentation for ``inspect`` <https://docs.python.org/3/library/inspect.html> and adjust the ``transformer.py:INSPECT_ATTRIBUTES`` list
* Add a corresponding changelog entry.
* Additionally modify ``.meta.toml`` and run the ``meta/config`` script (for details see: https://github.com/mgedmin/check-python-versions) to update the following files:

Expand Down
38 changes: 38 additions & 0 deletions src/RestrictedPython/transformer.py
Expand Up @@ -63,6 +63,35 @@
'breakpoint',
])

INSPECT_ATTRIBUTES = frozenset([
# inspect attributes:
# traceback
"tb_frame",
"tb_lasti",
"tb_lineno",
"tb_next",
# frame
"f_back",
"f_builtins",
"f_code",
"f_globals",
"f_lasti",
"f_lineno",
"f_locals",
"f_trace",
# generator
"gi_frame",
"gi_running",
"gi_code",
"gi_yieldfrom",
# coroutine
"cr_await",
"cr_frame",
"cr_running",
"cr_code",
"cr_origin",
])


# When new ast nodes are generated they have no 'lineno', 'end_lineno',
# 'col_offset' and 'end_col_offset'. This function copies these fields from the
Expand Down Expand Up @@ -844,6 +873,15 @@ def visit_Attribute(self, node):
'"{name}" is an invalid attribute name because it ends '
'with "__roles__".'.format(name=node.attr))

if node.attr in INSPECT_ATTRIBUTES:
self.error(
node,
'"{name}" is a reserved inspect attribute name, '
'that is forbidden to call in RestrictedPython'.format(
name=node.attr,
),
)

if isinstance(node.ctx, ast.Load):
node = self.node_contents_visit(node)
new_node = ast.Call(
Expand Down
50 changes: 26 additions & 24 deletions tests/test_generator_escape.py
@@ -1,5 +1,4 @@
from RestrictedPython import compile_restricted
from RestrictedPython import safe_globals
from RestrictedPython import compile_restricted_exec


def test_1():
Expand All @@ -17,32 +16,35 @@ def test():
os = leak.f_builtins.get('__import__')('os')
result = os.listdir('/')
# for visualization that it works -
# original example does not have a print on the listdir result
# but this should not affect the vulnerability
leak.f_builtins.get('print')(result)
"""
byte_code = compile_restricted(source_code, '<inline>', 'exec')
exec(byte_code, safe_globals, {})
"""
result = compile_restricted_exec(source_code)
assert result.errors == (
'Line 7: "f_back" is a reserved inspect attribute name, '
'that is forbidden to call in RestrictedPython',
'Line 7: "f_back" is a reserved inspect attribute name, '
'that is forbidden to call in RestrictedPython',
'Line 7: "gi_frame" is a reserved inspect attribute name, '
'that is forbidden to call in RestrictedPython',
'Line 12: "f_builtins" is a reserved inspect attribute name, '
'that is forbidden to call in RestrictedPython',
)


def test_2():
from RestrictedPython import Eval
from RestrictedPython import compile_restricted
from RestrictedPython import safe_globals
from RestrictedPython import utility_builtins
policy_globals = {**safe_globals, **utility_builtins}
policy_globals['_getiter_'] = Eval.default_guarded_getiter
policy_globals['_getitem_'] = Eval.default_guarded_getitem

source_code = """
q = (q.gi_frame.f_back.f_back.f_back for _ in (1,))
[x for x in q][0].f_builtins['__import__']('os').listdir('/')
result = [x for x in q][0].f_builtins['__import__']('os').listdir('/')
"""
byte_code = compile_restricted(
source_code,
filename="<string>",
mode="exec",
result = compile_restricted_exec(source_code)
assert result.errors == (
'Line 2: "f_back" is a reserved inspect attribute name, '
'that is forbidden to call in RestrictedPython',
'Line 2: "f_back" is a reserved inspect attribute name, '
'that is forbidden to call in RestrictedPython',
'Line 2: "f_back" is a reserved inspect attribute name, '
'that is forbidden to call in RestrictedPython',
'Line 2: "gi_frame" is a reserved inspect attribute name, '
'that is forbidden to call in RestrictedPython',
'Line 3: "f_builtins" is a reserved inspect attribute name, '
'that is forbidden to call in RestrictedPython',
)
exec(byte_code, policy_globals, None)

0 comments on commit ef41f33

Please sign in to comment.