/safeexec

A general-purpose lightweight sandbox for safely executing user programs

Primary LanguageCGNU Affero General Public License v3.0AGPL-3.0

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