# Run user code safely

I have to mark C code and part of that involves running and timing their submissions. The problem is that their code then runs as me and they can in principle do whatever they like using my permission settings. For example, they could copy my ssh private key.

I could set up a virtual machine and run their code within it (although I am not entirely sure of the best way to lock this down either). A problem with this is that the speed performance will now not be realistic. I could provide the same virtual machine to all the users to test their code on beforehand so at least they have the same set up to test with.

Is there a good way to set up an environment where you can run code written by others but limit the damage it can do?

-
If you run run this on a temporal account, which you created only for this purpose? –  Peter Horvath Dec 19 '13 at 10:20
@PeterHorvath That is a good idea. I would be very grateful for any tips on how to lock down such a temporary account. –  marshall Dec 19 '13 at 10:43
If it is a simple user, for him were practically impossible to do any really harmful. It were hard for a cracker even with an interactive shell. But if you delete the account after use, and kills all of its remaining processes (if remains, there is a good cause to a deeper look into its code), you are safe. (P.s. comments are upvotable, too :-) ) –  Peter Horvath Dec 19 '13 at 10:46
This belongs on security. –  l0b0 Dec 19 '13 at 11:54
@l0b0 Actually, it seems on topic here to me (though more specific answers might possibly be had on Unix & Linux). Running software isolated from the surrounding system is a perfectly reasonable request relating to a power user's use of computers. –  Michael Kjörling Dec 19 '13 at 12:01

There are actually multiple types of virtual machines, which is kinda being missed in the other answers. You can have what's known as container virtualisation - something like Linux vServer or OpenVZ. They share the host kernel, running what are known as 'containers' (with their own environments) rather than virtualising any hardware, and are almost as fast as bare metal. (OpenVZ is more common in cheaper VPS services, but only supports up to a custom kernel 2.6.x, while vServer goes up to latest stable).

Apart from that, the overhead of full virtualisation on a modern machine isn't as bad as you think! With hardware virtualisation on a mid-high end CPU, most uses wouldn't even notice any performance penalty, unless there was contention for resources (e.g. the host or another VM was using a lot). It will be a little slower, because some resources are used by the guest OS, but the cost of the virtualisation itself is almost negligible - especially CPU usage, since that can be passed to the raw hardware with (almost) no translation, if it's hardware accelerated. You could try it, you might be surprised.

Note that each also comes with differing levels of isolation. Container virtualisation makes it much easier to exploit kernel and other bugs to 'break out' of the container - LXC is not secure at all, though OpenVZ is considered pretty mature and secure (and is commonly used in VPS services, where you're selling containers to untrusted people). vServer is somewhere in between. Full virtualisation has better isolation, but some attacks still exist to break out.

It depends just how far you expect a malicious student to go. It might be sufficient to simply run as a different user. You might want a container for more security. Chances are that a container is enough for anything you'll encounter in these circumstances.

-

Make a single user account with limited privileges (which means access to only a limited set of library routines, possiby even a stripped down shell access).

ssh as the user in your system, and run their programs.

You can even write a small bash shell script (or any other shell script) to achieve this.

-
How well can you limit privileges? Ideally I would not allow the code to communicate over the network for example but that may be a step too far. –  marshall Dec 19 '13 at 10:42
to avoid them using the network you can use the owner match extension to iptables: see linuxpoison.blogspot.com.es/2010/11/… –  Carlos Campderrós Dec 19 '13 at 13:51
1. Run the code as nobody, which should give you minimal privileges. Depending on how hair-raising the configuration is, this may not be safe
2. Run in a chroot jail. Depending on the code this may change the behaviour, and jails can often be broken out of. They are not a security feature.
3. Run in a virtual machine. I think there are only very few known instances of being able to break out of those, but I'm not sure. You can use for example Vagrant to set up very simple virtualisation. Example configuration and commands.
-
Be careful. nobody is sometimes used by other processes, which would give you access to them as well. –  Bob Dec 19 '13 at 12:06
@Bob Good point! –  l0b0 Dec 19 '13 at 13:16

There's a few different possibilities, depending on how much isolation you want.

The easiest is to simply trust the code. It looks like that is out of the question for you, or you wouldn't be asking this.

The next step up is to run the code on a separate user account, as Vigneshwaren suggested. If you want to restrict network access specifically for a particular user account, that can be accomplished through iptables owner matching. When done, the user account can be left around or deleted, and any processes running as that user can be killed outright.

One more step up is to add a chroot jail to the separate user account. This can cause trouble with libraries or configuration files that need to be in place, but if it's e.g. a pure number-crunching exercise, it can be practical. It ensures that only the files you want the students' code to be able to access are accessible to that code.

The final step would be to execute the code in a completely separate environment. Think virtual machine, here, although a separate physical computer could accomplish the same thing. The code can execute in a completely isolated environment, including with the virtual network cable unplugged, and any damage it could possibly do, including filling up the disk or fork-bombing, will be isolated within the virtual machine and the worst that might happen is that you need to forcibly turn it off. Since the VM will have a completely separate OS installation, especially if you remove the network connection before running the software, this cannot possibly leak any of your sensitive data. With a VM, you can use disk snapshots to allow you to quickly and easily return to a known state after running each student's program.

It all depends on where on the effort-versus-trust-needed scale you place your students. Less trust requires more effort on your part to make sure nothing bad happens.

-
Thanks. I think in this case a separate account with, iptables and a chroot jail would be enough. Can you give some more details of how to get the chroot jail to work usefully? –  marshall Dec 19 '13 at 10:57
@marshall Sorry, that's just too broad. The most basic answer to that is "do chroot /mnt/chroot /bin/bash for some value of /mnt/chroot and fix whatever it complains about until it works for what you need". You'll likely need to populate it with a shell, some basic utilities, any necessary libraries and anything else the particular application needs. I suggest looking around and trying, and if you hit a roadblock ask a specific question about that. –  Michael Kjörling Dec 19 '13 at 11:58

I have to mark C code

Then you have full access to the source code, Look though it - its doubtful they will be able to pass off anything malicious in the code without you noticing.

If your unsure run it though a VM, but in most cases you will know what is being run

-
I refer you to underhanded.xcott.com :) –  marshall Dec 19 '13 at 14:31
@marshall Note that those deal with bugs in the program, not access outside the program. This is actually a pretty good suggestion if the programs are simple and not expected to have access to any system calls - because you can disable system calls in the compiler, preventing their use entirely, including any bugs in the system. However, if it's not a trivial program, this would be much harder. Also, you would have to trust that you've disabled everything necessary. –  Bob Dec 19 '13 at 16:34

I have worked on a similar system a few years ago. What I did was to use ptrace to limit the system calls (see code here), and optionally change user id or chroot. If the programs are simple, involving only pure algorithms and basic I/O tasks, this should be a practical solution that you could consider.

BTW, it is worth mentioning that you should also limit compiler time/memory usage. Some malicious programs may include directives like #include </dev/random> which could cause the compiler to hang for a long time, or some recursive macros causing the compiler to eat up lots of memory.

-
The OP wants to time the programs. Wouldn’t ptrace contaminate the timing? –  Scott Dec 21 '13 at 5:46
@Scott I think if CPU time instead of real time of the traced process is measured, and system calls are not very frequent, ptrace would not influence a lot. –  jiakai Dec 21 '13 at 5:52