This reminds me how, way back when, at one of the classes in my school we were expected to adhere to coding standards provided. Said coding standards prohibited the use of tabs throughout all files (the language expected was C). They further mandated all submissions to include a Makefile.
Taken literally, this would mean that tabs were forbidden in Makefiles, which as everyone knows makes it pretty impossible to do anything. But I found a way to circumvent this and have tab-less Makefiles that did what they were expected to do! Indeed, I wrote a converter from tabful to tabless Makefiles.
i.e. a Makefile containing one rule that does nothing, and defining a dummy eagerly-evaluated variable whose evaluation would write the actual makefile content to a file that takes precedence over the original one, and invoke make recursively on that. This took advantage of the fact that GNU make (nobody used anything else) looks at GNUmakefile first, then makefile, then Makefile.
I never got bonus points for this, but hey, now I have an amusing story!
Preventing arbitrary code from containing a syscall invocation seems like an uphill battle, but if the school controls the execution environment, it would much easier to just run the program through strace with the offending syscalls blocked.
Though I didn't mention it in the article, I did think of dlsym before looking into mmap but the issue is the same as execve, that is there is no symbol that is usable most of the time that lives in the same object as dlsym.
If we wanted to go further, an option would be to reimplement dlsym in user code, leak the base address of libc by reading /proc/<pid>/maps and load symbols. We still need what's done in the article to get open/read access.
This would work for pure C algorithmic exercises, but many of the exercises we have involve interacting with POSIX APIs. This would also make the compilation behaviour different between the students computers and the grader system.
I didn't mention it in the article, but usage of inline assembly is checked and banned before execution.
A lot of replies talk about filtering syscalls, it works but some exercises may need usage of those syscalls. It may become tedious to annotate every exercises with a whitelist of syscalls. I don't think my school will bother patching it.
nathell | 23 hours ago
This reminds me how, way back when, at one of the classes in my school we were expected to adhere to coding standards provided. Said coding standards prohibited the use of tabs throughout all files (the language expected was C). They further mandated all submissions to include a Makefile.
Taken literally, this would mean that tabs were forbidden in Makefiles, which as everyone knows makes it pretty impossible to do anything. But I found a way to circumvent this and have tab-less Makefiles that did what they were expected to do! Indeed, I wrote a converter from tabful to tabless Makefiles.
Here’s how it worked – it transformed this:
to this:
i.e. a Makefile containing one rule that does nothing, and defining a dummy eagerly-evaluated variable whose evaluation would write the actual makefile content to a file that takes precedence over the original one, and invoke make recursively on that. This took advantage of the fact that GNU make (nobody used anything else) looks at
GNUmakefilefirst, thenmakefile, thenMakefile.I never got bonus points for this, but hey, now I have an amusing story!
geocar | 14 hours ago
you can also use semicolon:
nathell | 14 hours ago
Well what do you know, this would have been much simpler! TIL, thank you!
zg | 17 hours ago
I'm trying to register in my mind why tabs would be prohibited, did you ever bother to ask?
nathell | 13 hours ago
I didn’t. I assumed this was an exercise in adhering to standards mandated by existing projects we’d encounter in real life.
jaculabilis | 16 hours ago
Preventing arbitrary code from containing a syscall invocation seems like an uphill battle, but if the school controls the execution environment, it would much easier to just run the program through
stracewith the offending syscalls blocked.classichasclass | 20 hours ago
So, c'mon, what did your school say when they saw you try this? The story is unfinished! ;)
treykeown | 15 hours ago
Love the cat-and-mouse game of casual sandboxing like this. My guess would be that
dlsym(RTLD_NEXT, "execve")should work as well.invlpg | 15 hours ago
Only if
dlsymis an allowed symbol.[OP] mrnossiom | 3 hours ago
Though I didn't mention it in the article, I did think of
dlsymbefore looking intommapbut the issue is the same asexecve, that is there is no symbol that is usable most of the time that lives in the same object asdlsym.If we wanted to go further, an option would be to reimplement
dlsymin user code, leak the base address oflibcby reading/proc/<pid>/mapsand load symbols. We still need what's done in the article to getopen/readaccess.accelbread | 20 hours ago
Seems like the system could handle this by compiling the code to wasm, with only the allowed stdlib functions allowed for import.
[OP] mrnossiom | 6 hours ago
This would work for pure C algorithmic exercises, but many of the exercises we have involve interacting with POSIX APIs. This would also make the compilation behaviour different between the students computers and the grader system.
kriive | 14 hours ago
Awesome article! Did you try to run something like this?
As for how to mitigate this, the sandbox could try to use seccomp. Ideally it should allow only a subset of the syscalls (i.e. not
execve)[OP] mrnossiom | 6 hours ago
I didn't mention it in the article, but usage of inline assembly is checked and banned before execution. A lot of replies talk about filtering syscalls, it works but some exercises may need usage of those syscalls. It may become tedious to annotate every exercises with a whitelist of syscalls. I don't think my school will bother patching it.
sammko | 11 hours ago
This reminded me of ioi/isolate which tries to solve a very similar use case for IOI competitions.
https://github.com/ioi/isolate
Shorden | 7 hours ago
My school had the prescient idea to solicit feedback from CTF players to help strengthen their sandboxing implementations.
icefox | 2 hours ago
something something system call capabilities something something