-
-
Notifications
You must be signed in to change notification settings - Fork 39
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
Multiple binary support api #196
Conversation
1b512b8
to
5f67817
Compare
b990ac2
to
c97b74d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add something in the readme about multiple version support? Can just be a blurb I think.
snekbox/api/resources/eval.py
Outdated
if binary_path: | ||
binary_path = Path(binary_path) | ||
if ( | ||
not binary_path.resolve().as_posix().startswith("/lang/") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why restrict it to just files in that directory? It seems like an arbitrary restriction I don't think we should have.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I missed this in your description
if supplied, snekbox ensures that the path is within /lang (to avoid executing arbitrary binaries on the fs) and that the file exists.
It is fairly trivial to bypass this restriction by using the execve
syscall. We cannot block this syscall either (at least not through nsjail's seccomp filters). That is due to a quirk in which the filter is applied before nsjail's own execve
call, causing nsjail to commit suicide.
Granted, there may be use cases which don't have binaries in /lang
that make it possible to call syscalls. But I think if a request comes up to have such restriction, we can add it as a later feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
snekbox/api/resources/eval.py
Outdated
not binary_path.resolve().as_posix().startswith("/lang/") | ||
or not binary_path.is_file() | ||
): | ||
raise falcon.HTTPBadRequest(title="binary_path file is invalid") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's be more specific. We should also check that the file exists if we aren't already (and that should be a distinct error message)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
snekbox/nsjail.py
Outdated
""" | ||
if not binary_path: | ||
binary_path = "/lang/python/default/bin/python" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's set the default in the function parameters instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had to do something slightly idfferent so that hte default cna be used both by calling python3 directly, and when calling the API 66c6d27
snekbox/nsjail.py
Outdated
@@ -188,7 +189,12 @@ def python3( | |||
py_args: Arguments to pass to Python. | |||
files: FileAttachments to write to the sandbox prior to running Python. | |||
nsjail_args: Overrides for the NsJail configuration. | |||
binary_path: The path to the binary to execute under. | |||
If None, defaults to "/lang/python/default/bin/python" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should rename /lang
since it's going to be more prominent now. Maybe /snekbin
? — doubles as a kinda clever play on "snekbox". If so, we also have to rename our references to the path in our CONTRIBUTING.md docs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I agree this is a good change f726695
tests/test_integration.py
Outdated
"""Test that passing invalid binary paths result in no code execution.""" | ||
with run_gunicorn(): | ||
cases = [ | ||
("/bin/bash", "test files outside of /lang cannot be ran"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
("/bin/bash", "test files outside of /lang cannot be ran"), | |
("/bin/bash", "test files outside of /lang cannot be run"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tests/test_integration.py
Outdated
"/lang/../bin/bash", | ||
"test path traversal still stops files outside /lang from running", | ||
), | ||
("/foo/bar", "test non-existant files are not ran"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
("/foo/bar", "test non-existant files are not ran"), | |
("/foo/bar", "test non-existant files are not run"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a784d78
to
6dcf094
Compare
I plan to pick this PR up soon just had time to rebase this evening |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really cool!!!
snekbox/api/resources/eval.py
Outdated
binary_path = Path(binary_path) | ||
if ( | ||
not binary_path.resolve().as_posix().startswith("/lang/") | ||
or not binary_path.is_file() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also check that it's executable?
or not binary_path.is_file() | |
or not binary_path.is_file() | |
or not binary_path.stat().st_mode & 0o100 == 0o100 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! 81573b2
snekbox/api/resources/eval.py
Outdated
if binary_path: | ||
binary_path = Path(binary_path) | ||
if ( | ||
not binary_path.resolve().as_posix().startswith("/lang/") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we move the resolve().as_posix()
calls above so the pathlib calls below can make use of it? Or do they mutate the internal object (source of eldritch horrors)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed this func quite a bit since then, so this is no longer relevant
Hey how's this PR going? It would be very useful for a project I'm working on. |
This is needed as dev builds such as 3.13-dev use the suffix -dev, rather than a patch version.
6dcf094
to
39c3e79
Compare
This was needed due to wanting a default value when calling python3 diurectly, but also when not specified via the API call
39c3e79
to
f726695
Compare
Now ready for (re)review |
snekbox/api/resources/eval.py
Outdated
@@ -43,6 +44,7 @@ class EvalResource: | |||
"required": ["path"], | |||
}, | |||
}, | |||
"binary_path": {"type": "string"}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe "executable_path" is a better name than "binary_path"? I'm also okay with the latter though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I agree, makes it clearer what is supported here, as it's not limitted to just binaries. edcaed6
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks!
This allows setting a
binary_path
key in the request body to/eval
to specify which binary to run under.If not supplied, it defaults to
"/snekbin/python/default/bin/python"
.0c9b234 is needed as previously we were dropping the text after the last period when creating the path to install Python to. However, for versions such as3.13-dev this would result in it being installed into
/snekbin/3
. Instead, we now split on the last.
or the last-