Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decide if safe way to serialize QuestionFunctional #429

Open
johnjosephhorton opened this issue May 5, 2024 · 3 comments
Open

Decide if safe way to serialize QuestionFunctional #429

johnjosephhorton opened this issue May 5, 2024 · 3 comments
Assignees

Comments

@johnjosephhorton
Copy link
Contributor

QuestionFunctional takes a func parameter that is a python function. Obviously, we cannot just eval this back to life from serialized form. But perhaps with enough safety checks, we could serialize a function if we were sure it was purely functional w/ no side effects.

@zer0dss this is more your lane - any ideas? Is there some safe way for us to do this?

E.g., here's a ChatGPT idea

import ast

def is_safe_to_eval(func):
    def visit_node(node):
        # Allow only the following safe node types
        safe_nodes = (
            ast.FunctionDef,
            ast.arguments,
            ast.arg,
            ast.Load,
            ast.Expr,
            ast.BinOp,
            ast.UnaryOp,
            ast.Num,
            ast.Str,
            ast.Name,
            ast.Call,
            ast.keyword,
            ast.List,
            ast.Tuple,
            ast.Set,
            ast.Dict,
            ast.Compare,
            ast.Attribute,
            ast.Index,
            ast.Slice,
            ast.Subscript,
            ast.Lambda,
            ast.Return,
            ast.Pass,
        )
        for child in ast.iter_child_nodes(node):
            if isinstance(child, ast.Assign) or isinstance(child, ast.AugAssign):
                return False
            if not isinstance(child, safe_nodes):
                return False
            if not visit_node(child):
                return False
        return True

    source_code = inspect.getsource(func)
    parsed_ast = ast.parse(source_code)
    return visit_node(parsed_ast)

@zer0dss
Copy link
Collaborator

zer0dss commented May 5, 2024

@johnjosephhorton A solution that I've seen in CTF challenges is RestrictedPython. It blocks all the dangerous methods that could lead to a server compromise.

Observation: By default RestrictedPython blocks for loops too because it can create infinite code logic that consumes the CPU. If we want to allow the user to use for loops then we can implement a protection by setting a limit execution time for the method.

@johnjosephhorton
Copy link
Contributor Author

Interesting - is the loop execution restriction part of RestrictedPython or would we have to add that ourselves?

@zer0dss
Copy link
Collaborator

zer0dss commented May 5, 2024

We have to run the code in a thread with execution time limit. This is the solution that we have to add. RestrictedPyhon doesn't provide this by default and just suggests that you have to choose your own strategy when allowing for loops.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants