zopefoundation / RestrictedPython

A restricted execution environment for Python to run untrusted code.
http://restrictedpython.readthedocs.io/
Other
456 stars 38 forks source link

Unable to compile single expressions #271

Closed kuwv closed 5 months ago

kuwv commented 6 months ago

PROBLEM REPORT

Attempted a simple compile_restricted using single.

x = 50
code = compile_restricted('x + 25', '<string>', 'single')

What I did:

Attempted a simple comparison with compile(). Also, compared it with exec.

x = 50
code = compile('x + 25', '<string>', 'single')
exec(code)

assert x == 75

What I expect to happen:

Should be able to compile a single expression and execute with the associated side-effects similar to compile().

What actually happened:

SyntaxError: ('Line None: Interactive statements are not allowed.',)

What version of Python and Zope/Addons I am using:

Python 3.11.8 RestrictedPython 7.0

icemac commented 6 months ago

The documentation is not clear about what this single mode is. There is even a test which asserts the error message you are seeing.

Maybe you have to use eval mode, even though it works totally different.

cc @loechel – Do you have an explanation for the single mode and the degree RestrictedPython supports it?

d-maurer commented 6 months ago

Michael Howitz wrote at 2024-2-26 23:51 -0800:

... cc @loechel – Do you have an explanation for the single mode and the degree RestrictedPython supports it?

"single" is mostly used as support for the interactive interpreter; it compiles a single line containing a sequence of simple statements or one complex statement (potentially spanning multiple lines).

I do not think, we need support for it in RestrictedPython.

loechel commented 6 months ago

@icemac as we ported RestrictedPython the Interactive mode was not implemented.

It could be easily done by adding a visit_Interactive to the transformer.py. Documentation for it: https://docs.python.org/3/library/ast.html#ast.Interactive

    def visit_Interactive(self, node):
        """Allow single mode without restrictions."""
        return self.node_contents_visit(node)

corresponding test:

def test_compile__compile_restricted_csingle_allowed():
    """It compiles code as an Interactive."""
    result = compile_restricted_single('4 * 6')

    assert result.errors == ()
    assert result.warnings == []
    assert exec(result.code) == 24
kuwv commented 6 months ago

@loechel Thank you.

I would appreciate this being implemented. Should I submit an MR or will someone else here assist?

loechel commented 6 months ago

@kuwv I could do a merge request and bring it into one of the next releases, if @icemac agrees.

I guess, you @kuwv don't have signed the Zope Contributer Agreement, it would take more overhead for you to submit a Merge Request to get it included.

icemac commented 6 months ago

@loechel I agree that you can come up with a PR.

loechel commented 6 months ago

merge request created, after some more tests, I have seen, that the invocation is a bit different than asked for.

code = compile_restricted('x = 4 * 6', filename="<string>", mode="single")
locals = {}
exec(code, {}, locals)
assert locals["x"] == 24

to explain. exec does not return anything but prints.

kuwv commented 6 months ago

merge request created, after some more tests, I have seen, that the invocation is a bit different than asked for.


code = compile_restricted('x = 4 * 6', filename="<string>", mode="single")

locals = {}

exec(code, {}, locals)

assert locals["x"] == 24

to explain. exec does not return anything but prints.

Yeah, that's correct. The 'tests/helper.py' implements an exec return.