safeexec (safe execution environment) A general-purpose lightweight sandbox for safely executing user programs https://github.com/cemc/safeexec History: see below. License: AGPL 3 (http://www.gnu.org/licenses/agpl.html) safeexec provides a sandbox environment which prevents malicious users from causing trouble, and user mistakes from blowing up your server. However, running code on your server should be taken at __your own risk__. You should take these additional precautions: - check whether safeexec default gid (1000)/uids (10000-42768) are in use! - assuming not, you may name the group, but you won't name the users; the whole user range is treated as "unpriviliged" ("other" for all files) - this code doesn't block network access. Use iptables to do this, e.g.: /sbin/iptables -A OUTPUT -m owner --gid-owner 1000 -j DROP - the max number of file handles (nfile) needs to be nonzero in order to read libraries, but even if the maximum file size (fsize) is 0, the code can go around creating size-0 files. Use file permissions to avoid this, and to avoid reads as well. Chroot can limit how much of a "file system" they can see at all. The general plan: - fork into two processes - safeexec should have its setuid bit on, and uid root - one fork will be a supervisor running as root - other fork runs program as unprivileged user, with rlimits & nice - supervisor will measure total memory by looking in /proc/ - wall clock limit enforced with alarm() & signal() - return EXIT_SUCCESS (0) if all went ok, EXIT_FAILURE otherwise Standard input to safeexec is passed on to the exec'd process. The non-supervisor user number is determined by the supervisor process: <non-supervisor uid #> = 10000 + <supervisor pid #> or, you can replace 10000 with something else using uidplus. Since pids are unique, so are the resulting uids. (Sanity check: max value of pids is in /proc/sys/kernel/pid_max) Among other things, this should prevent simultaneous safeexec'ed programs from kill()ing each other, which they could do if they had the same user id. INSTALLATION make # requires sudo access USAGE ./safeexec # run with no options to see arguments EXAMPLES See the file EXAMPLES. For a basic test, run: cd tests; make; cd .. # compile "hello world" etc ./safeexec --exec tests/hello Expected result (stdout + stderr mixed): Hello World OK elapsed time: 0 seconds memory usage: 0 kbytes cpu usage: 0.000 seconds See EXAMPLES-CHROOT and EXAMPLES-ETC for more examples and tests. USAGE NOTES AND TROUBLESHOOTING Chroot is powerful stuff: it makes a given directory (say, /jail) appear to be the root directory of the file system, as far as the child process can see. However, the jail directory might need to be given further files, in order for the child process to operate correctly. For example, a Python3 jail needs to include some unexpected things like /lib/libcrypt-2.5.so. Make sure that you set the file and memory limits big enough that your language can load. Python can give you all manner of strange errors if it doesn't get enough memory. Note: A user who had been utilizing proxmox containers/LXC reported that installing safeexec was not possible until they switched to a KVM. PARANOID DISCLAIMER You can get more fine-grained supervision if you ptrace, which interrupts every system call (at a cost of more overhead). Use a VM if you are more paranoid. Use separate machines if you want to avoid timing attacks. TODO Linux provides, in principle, two ways to measure the time used by a process. According to "Security of Programming Contest Systems" by Michal Fori\v{s}ek, only one of these is suitable. It seems we should use prctl() to change PR_SET_TIMING to PR_TIMING_TIMESTAMP but, this is apparently just defined, and not yet implemented, in linux. HISTORY Originally part of Mooshak (http://mooshak.dcc.fc.up.pt/) Revised in 2009 by http://github.com/ochko/safeexec This version revised in 2011-13 by David Pritchard (daveagp@gmail.com) http://github.com/daveagp Mooshak released the files under "The Artistic License". The main changes made to safeexec.c are - how are uids calculated (pid + a constant) which avoids two different web users getting the same uid - allow setting group id - bugfix: remove all supplemental groups - command-line argument for niceness - command-line argument for environment variables This changed version is released under the GNU Affero General Public License, versions 3 or later. See LICENSE or visit: http://www.gnu.org/licenses/agpl.html