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

fix: replace eval with a safer alternative #147

Conversation

HarikrishnanBalagopal
Copy link
Contributor

@HarikrishnanBalagopal HarikrishnanBalagopal commented May 3, 2024

Description of the change

Use the AST module to evaluate the rules instead of eval.

  1. We use the Python AST library to parse the code.
  2. We use this library https://github.com/danthedeckie/simpleeval for traversing and evaluating the generated AST.
  3. The output of evaluation should be a boolean value which we return indicating if the rule succeeded.

Example supported expressions: https://github.com/danthedeckie/simpleeval?tab=readme-ov-file#operators

Support for more complex types (list, dict, etc.) are also implemented:

Notes:

  • PyPi https://pypi.org/project/simpleeval/ (MIT Licence)
  • Array Multiplication ["hello"]*10 is allowed but limited to smaller numbers to avoid Denial of Service (DOS).
  • List comprehension is allowed but limited to small number of iterations to avoid DOS.
  • Exponentiation 9**9 is allowed but limited to smaller numbers to avoid DOS.
  • Access to double underscore attributes like __class__ is disallowed to avoid access to arbitrary classes like Quitter.
  • Lambda expressions are disallowed for simplicity and to reduce the attack surface. Can be added back in if necessary.
  • Access to builtin functions and globals are disallowed expect for int, float, str, rand and randint.
  • Has support for accessing keys in dicts using the short syntax:foo.bar . Example dict: {"foo": {"bar": 42}})

Related issue number

Fixes #148

How to verify the PR

Have added unit tests for the safe evaluator.

make test

Was the PR tested

  • I have added >=1 unit test(s) for every new method I have added.
  • I have ensured all unit tests pass

@HarikrishnanBalagopal HarikrishnanBalagopal changed the title fix: replace eval with safer alternative fix: replace eval with a safer alternative May 3, 2024
@HarikrishnanBalagopal HarikrishnanBalagopal marked this pull request as draft May 4, 2024 06:27
@HarikrishnanBalagopal HarikrishnanBalagopal force-pushed the fix/simpleeval branch 7 times, most recently from fef6e45 to fa48a53 Compare May 8, 2024 09:31
@HarikrishnanBalagopal HarikrishnanBalagopal marked this pull request as ready for review May 8, 2024 09:37
@HarikrishnanBalagopal HarikrishnanBalagopal force-pushed the fix/simpleeval branch 4 times, most recently from 091ea3f to 1c14a3e Compare May 8, 2024 15:17
Copy link
Collaborator

@alex-jw-brooks alex-jw-brooks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is a really interesting contribution - a lot of questions and one request to split the PR up a little 😄

architecture_records/001-trainer-controller-framework.md Outdated Show resolved Hide resolved
tuning/trainercontroller/callback.py Show resolved Hide resolved
@@ -59,6 +67,21 @@
CONTROLLER_OPERATIONS_KEY = OPERATIONS_KEY


def get_evaluator(metrics: dict) -> EvalWithCompoundTypes:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any thoughts on making this part of the class, e.g., as a staticmethod? It feels a bit strange to me to store it separately here like this

Copy link
Contributor Author

@HarikrishnanBalagopal HarikrishnanBalagopal May 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EvalWithCompoundTypes is coming directly from the library.
Making it a static method would require overriding the class.
Since this is just a utility function I have moved it to a more appropriate location.
We can also remove the function entirely if necessary.

tuning/trainercontroller/callback.py Outdated Show resolved Hide resolved
tuning/trainercontroller/callback.py Show resolved Hide resolved
tests/trainercontroller/test_simpleeval.py Outdated Show resolved Hide resolved
docs: update documentation with the new format for controller metrics and operations and details of rule evaluation

Signed-off-by: Harikrishnan Balagopal <harikrishmenon@gmail.com>
Copy link
Collaborator

@alex-jw-brooks alex-jw-brooks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. LGTM, thanks!

tuning/trainercontroller/callback.py Show resolved Hide resolved
@alex-jw-brooks alex-jw-brooks merged commit 80ffb83 into foundation-model-stack:main May 14, 2024
6 checks passed
jbusche pushed a commit to jbusche/fms-hf-tuning that referenced this pull request May 21, 2024
docs: update documentation with the new format for controller metrics and operations and details of rule evaluation

Signed-off-by: Harikrishnan Balagopal <harikrishmenon@gmail.com>
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

Successfully merging this pull request may close these issues.

bug: eval is still not safe even with checks for __ and "__builtins__": None
2 participants