9

I want to set up a server on which students can upload and run code for a course. However, I don't want them to access various functions, like system(), which could allow bad access to my server. I can search the pre-processor output for an explicit function call, but if the user makes a function pointer like this:

int (*syst)(const char*) = system;
syst("rm *");

I'm still open to the threat. However, I can't just search for the string "system", for example, since it's otherwise a valid name - if the student didn't include cstdlib, they could use that name as a variable name. Since this is a beginning programming course, having a blacklist of variable names ten miles long is a bad idea.

Is there a way to define the functions other than by name and allow me to search for that other designation before compiling their code?

Michael Stachowsky
  • 717
  • 1
  • 5
  • 21
  • Generally C/C++ is not designed for safe execution (sandbox aka jail). I think, You can provide fake library with empty functions system etc, or/and made guard in operating system (but has nothing to student code, compilation) – Jacek Cz Jul 28 '16 at 14:23
  • 1
    Perhaps use seccomp / seccomp-bpf. https://en.m.wikipedia.org/wiki/Seccomp – Jesper Juhl Jul 28 '16 at 14:25
  • That looks promising, thanks! – Michael Stachowsky Jul 28 '16 at 14:25
  • 2
    Why not run these programs in a VM? There are a few free ones available. They don't need to have many resources, and the student programs can call whatever they want. If they ruin the setup, you delete this VM and run a clone you made before. On my Mac, I have a Linux and a few Windows VM just for that.. – Rudy Velthuis Jul 28 '16 at 14:26
  • It's already running in a VM. My major concerns are that the code may be used to do something illegal or the student may manipulate the environment to, for example, always pass the tests and therefore cheat. – Michael Stachowsky Jul 28 '16 at 14:28
  • 1
    If they are clever enough to cheat, they should pass anyway. Just kidding. – Rudy Velthuis Jul 28 '16 at 14:29
  • 1
    :-P To be honest, I sort of want to set up a box that is vulnerable in some ways, intentionally. If they can get past the security, then they get full marks. Why not? If they are good enough at it, they should be rewarded haha – Michael Stachowsky Jul 28 '16 at 14:31
  • You can try system used for competitive programming contests - online judge systems. There are several offline judge system (even open source). C++ allows execution of asm code and properly exploited undefined behaviour is even harder to find. – Serikov Jul 28 '16 at 14:33
  • 1
    may be you can use an old trick #define system void –  Jul 28 '16 at 14:33
  • ["It's already running in a VM."](http://stackoverflow.com/questions/38639102/c-can-function-pointers-be-traced-back-to-the-original-function-before-compil#comment64661650_38639102) But isn't a VM exactly what should protect against "code that may be used to do something illegal"? I don't really see why a virtual machine should not suffice. – cadaniluk Jul 28 '16 at 14:36
  • Not really. They can break my VM all they want - the reason I used the VM in the first place was so that if they did anything malicious to the VM itself, I can just roll it back. I'm mainly concerned that they will, say, install a spam server or something. If that happens, sure I can just roll it back, but the security vulnerability is in the rolled-back version anyway, so I'd have to protect it. I think that this is really a linux-level problem, instead of the C++ problem I thought it was originally – Michael Stachowsky Jul 28 '16 at 14:37
  • 1
    Could [cms judge](http://cms.readthedocs.io/) or [PC^2](http://pc2.ecs.csus.edu/pc2code.html) provide what you want? – Serikov Jul 28 '16 at 14:39
  • Possibly. I'll look into the open-source stuff as well. However, we have fairly specific requirements that may mean that no existing solution does everything. We've already tried one that would almost work but not quite for what we wanted, and modifying it would be too difficult given how it's set up – Michael Stachowsky Jul 28 '16 at 14:40
  • 1
    Well, you should also prevents inline assembly, because it is trivial to reimplement `fork()` and `exec()` in assembly, and then write your own version of `system()`. You should look into the `linux-user-chroot` command which can remove the network stack, IPC, and so on, from the chroot. – fjardon Jul 28 '16 at 15:37

2 Answers2

3

By far the easiest solution is to compile the code - that's pretty harmless - and then look at the actual library imports. Users may have defined their own system, but that wouldn't cause system to be imported from glibc.

Showing imported symbols

The main reason you can't look at the raw source code is because #define allows malicious users to hide the blacklisted symbol names. But there are plenty of other possibilities to do that, including

auto hidden = &sys\
tem;

So you need some processing of the source, and it's probably easiest just to fully process the whole source.

Community
  • 1
  • 1
MSalters
  • 173,980
  • 10
  • 155
  • 350
1

I would also suggest running this inside a chroot as a non-privileged user. It's lighter weight than a VM.

Alas, it's not possible (easily) to get a functions name from a pointer How to get function's name from function's pointer in C? That question is from a C perspective, but it's the same problem, essentially.

Community
  • 1
  • 1
Joshua Smith
  • 6,561
  • 1
  • 30
  • 28