Open Abdullahsecuriti opened 1 month ago
Abdullahsecuriti wrote at 2024-8-2 10:42 -0700:
Description:
In a restricted Python package environment, the following code snippet:
python Copy code
try: exec("import os; os.system('ls'); print('**')") except: pass
successfully executes without throwing an error, despite exec being expected to be undefined in such a restricted environment.
exec
is undefined (if you do everything right, see below)
and the access raises a NameError
which you ignore with your try: ... except: ...
.
However, when the code is run without the try-except block:
python Copy code
exec("import os; os.system('ls'); print('**')")
an error is thrown as expected.
You get the exception in this case because you do not ignore exceptions here.
Expected Behavior:
The restricted environment should prevent the execution of exec and throw an error when it is invoked, regardless of the surrounding try-except block.
Your expectation is wrong:
(unlike for Python 2) exec
is a function (in Python 3) and RestrictedPython
has no need to treat is specially.
When you execute restricted code, you typically supply an
execution environment (via the globals
parameter of exec
)
with a limited builtins set (especially not containing exec
).
If your restricted code references exec
(during execution)
and exec
is not in the execution environment, you
will get a NameError
(which might get try: ... except:
ed).
For your future problem reports: please provide FULL code snippets reproducing the problem. In your current report, you supply the restricted code but not how it is compiled nor in what execution environment it is executed. The code you provide should allow to run it (after extraction) and then reproduce the problem.
@d-maurer Thank you for your quick response; it's highly appreciated.
I have successfully executed the following code:
async def __main():
# Import necessary modules from RestrictedPython
import textwrap
from RestrictedPython import compile_restricted, safe_builtins
from RestrictedPython.Utilities import utility_builtins
from RestrictedPython.Eval import default_guarded_getattr
def execute_restricted_code(user_code):
try:
# Format the user-provided code
formatted_code = textwrap.dedent(user_code)
# Define safe globals for restricted code execution
safe_globals = {
'__builtins__': safe_builtins, # built-in policy allowing basic Python functions
}
# Compile the normalized and formatted user-provided code into a restricted code object
restricted_code = compile(formatted_code, '<usercode>', 'exec')
# Create a list to capture printed output
captured_output = []
# Define a custom print function to capture output
def safe_print(*args, **kwargs):
output = ' '.join(str(arg) for arg in args)
captured_output.append(output)
# Execute the restricted code within the restricted context
exec(restricted_code, safe_globals, {'print': safe_print})
# Print the captured output directly within the function
for line in captured_output:
print(line)
return '\n'.join(captured_output), None
except Exception as e:
error_message = f"Error executing restricted code: {e}"
print(error_message)
return None, error_message
# This is User Input from Node
user_code = '''
def restrictedPythonMain():
try:
# Attempt to use a restricted operation (e.g., system command or file access)
restricted_operation = lambda: exec("print('hello world')")
restricted_operation()
except:
# Catch any exceptions that indicate unauthorized access is prevented
pass
restrictedPythonMain()
'''
result, error_message = execute_restricted_code(user_code)
if result is None:
errorHandler = [{'error': str(error_message)}]
return errorHandler
await __main()
While this code executes successfully, it allows the use of the exec function, which is not intended. I observed the output "hello world" on the console, indicating that restricted functions were not blocked as expected.
However, when the user_code is as follows, an error is thrown due to the use of the exec function, which is the desired behavior:
user_code = '''
def restrictedPythonMain():
exec("print('hello world')")
restrictedPythonMain()
'''
Could you please advise on what might be incorrect in my implementation? I aim to prevent users from calling functions like exec in any context within the restricted environment.
Thank you for your assistance.
Abdullahsecuriti wrote at 2024-8-3 05:40 -0700:
I have successfully executed the following code:
async def __main():
Import necessary modules from RestrictedPython
import textwrap from RestrictedPython import compile_restricted, safe_builtins ... def execute_restricted_code(user_code): try:
Format the user-provided code
formatted_code = textwrap.dedent(user_code) # Define safe globals for restricted code execution safe_globals = { '__builtins__': safe_builtins, # built-in policy allowing basic Python functions } # Compile the normalized and formatted user-provided code into a restricted code object restricted_code = compile(formatted_code, '<usercode>', 'exec')
Why are you using compile
here (instead of compile_restricted
)?
With compile
you get unrestricted code (likely not intended
as you assign it to a variable named restricted_code
).
... exec(restricted_code, safe_globals, {'print': safe_print})
Even though your code is unrestricted, you should still
get a BameError: name
execis not defined
because
you execution environment does not contain exec
.
For a verification, I simplified your (overly complex) code:
from RestrictedPython import compile_restricted, safe_builtins
safe_globals = {'__builtins__': safe_builtins, 'print': print}
src = """
def f():
exec("print('hello')")
f()
"""
code= compile(src, "usercode", "exec")
ld = {}
exec(code, safe_globals, ld)
It raises the expected exception.
I suggest you replace compile
by compile_restricted
(to get restricted code)
and then start from my example code to reproduce the problem.
Keep it as simple as possible (but still showing the problem).
Avoid artificial function definitions (e.g. lambda
s).
BUG/PROBLEM REPORT / FEATURE REQUEST
Description:
In a restricted Python package environment, the following code snippet:
python 3.10.0
successfully executes without throwing an error, despite exec being expected to be undefined in such a restricted environment.
However, when the code is run without the try-except block:
exec("import os; os.system('ls'); print('**')")
an error is thrown as expected.Expected Behavior:
The restricted environment should prevent the execution of exec and throw an error when it is invoked, regardless of the surrounding try-except block.