Beware this can be used for security-purposes, but it can deliberately be circumvented. Soapbox only impacts dynamically linked programs that properly use glibc functions. I'm currently looking into a safer implementation using ptrace.
Soapbox also triggered some bugs in applications that trusted system calls too much. So you can use soapbox to test your programs for these kinds of mistakes too.
According to the Jargon File, a sandbox is "A controlled environment within which potentially dangerous programs are run.".
My aim was to try to complete the build-process as successful as possible, and present the builder with all the errors that occured. The most important fact being to automate as much as possible (creating automated mails for upstream developers, building large sets of packages automatically). Reducing the time to fix broken scripts and reducing the number of broken builds before a clean package is created. Time is precious.
Soapbox is optimized with that purpose in mind.
- Define one or more directories where write-access is allowed (SOAPBOXPATH)
- Define a logfile (so that output won't disturb programs) (SOAPBOXLOG)
- 3 types of action to be taken on illegal (write) access (SOAPBOXACTION)
- warn: report and fake successful completion of illegal systemcalls (default)
- err: report and return access denied
- halt: exit the process successfully immediately
- Extensive runtime debugging options (SOAPBOXDEBUG)
- program execution
- library calls
- overloaded systemcalls
- internal functions (rewriting files)
- A Soapbox wrapper script is available for your pleasure
Usage: soapbox [-cfhsv] [-a action] [-d level] [-l file] [-p paths] [--] command Soapbox - A way to deny processes to write files outside some directories -a action action is one of 'warn', 'err' or 'halt' -c add current working directory to path -d debuglevel a number between 0 and 31 (1-4 bitwise) -f overwrite logfile (instead of appending) -h display this help and exit -l logfile log to a logfile -p paths list of directories to which writing is allowed -s safe path (eg. /dev/tty, /dev/null, /tmp, /var/tmp) -v output version information and exit Example: soapbox -l log -p /tmp:/var/tmp/ -- make DESTDIR=/var/tmp install Report bugs to: Dag Wieers <firstname.lastname@example.org>.
So I open up /tmp for compilation: (In this case I could have allowed only eg. /tmp/cc)# soapbox make all install gcc -g -Wall -fPIC libsoapbox.c -nostartfiles -shared -rdynamic \ -Wl,-soname,libsoapbox.so -o libsoapbox.so -ldl -lm soapbox: Attempt to open("/tmp/ccI0TsPz.s", O_RDWR|O_EXCL|O_CREAT, 0600). soapbox: Attempt to open("/tmp/ccITDyyh.o", O_RDWR|O_EXCL|O_CREAT, 0600). make: *** [libsoapbox.so] Aborted
I now noticed that it is trying to install in /lib, but that's not what I want. Let's put everything in /var/tmp/soapbox, please.# soapbox -p /tmp make all install gcc -g -Wall -fPIC libsoapbox.c -nostartfiles -shared -rdynamic \ -Wl,-soname,libsoapbox.so -o libsoapbox.so -ldl -lm soapbox: Attempt to chmod("/usr/src/soapbox-0.0.7/libsoapbox.so", 0755). install -d -m0755 /lib /usr/bin soapbox: Attempt to chmod("/lib", 0755). soapbox: Attempt to chmod("/lib", 0755). soapbox: Attempt to chmod("/usr/bin", 0755). soapbox: Attempt to chmod("/usr/bin", 0755). install -m0755 libsoapbox.so /lib soapbox: Attempt to unlink("/lib/libsoapbox.so"). soapbox: Attempt to open64("/lib/libsoapbox.so", O_WRONLY|O_CREAT, 100644). soapbox: Attempt to chmod("/lib/libsoapbox.so", 0600). soapbox: Attempt to chown("/lib/libsoapbox.so", -1, -1). soapbox: Attempt to chmod("/lib/libsoapbox.so", 0755). install -m0755 libsoapbox.sh /usr/bin/soapbox soapbox: Attempt to unlink("/usr/bin/soapbox"). soapbox: Attempt to open64("/usr/bin/soapbox", O_WRONLY|O_CREAT, 100644). soapbox: Attempt to chmod("/usr/bin/soapbox", 0600). soapbox: Attempt to chown("/usr/bin/soapbox", -1, -1). soapbox: Attempt to chmod("/usr/bin/soapbox", 0755).
PS: Sadly install is doing some useless things, eg. too many chmod()s and some mkdir()s that are unnecessary.soapbox -p /tmp:/var/tmp/soapbox make all DESTDIR="/var/tmp/soapbox" install make: Nothing to be done for `all'. install -d -m0755 /var/tmp/soapbox/lib /var/tmp/soapbox/usr/bin soapbox: Attempt to mkdir("/var", 0755). soapbox: Attempt to mkdir("/var", 0755). install -m0755 libsoapbox.so /var/tmp/soapbox/lib install -m0755 soapbox.sh /var/tmp/soapbox/usr/bin/soapbox
The current implementation has some problem corner cases though. For instance, some processes open files O_RDRW but only read from it. At the moment, this will be denied although theoretically we could allow it by overloading write and tracking some things. The BUGS file states some other cases that we could improve.
There is some more documentation inside the package.
syscalltrack, which is able to do the same (and much more) within the kernel. (But not on a per process level and it doesn't work with recent RH kernels)
There are possibly other ways to work around the overloaded functions, yet it is still useful together with the normal file-permissions. To fake succesful completion for changes that a user can't possibly make because of permissions.
Another issue regarding hardlinks: hard-links inside the safe-path allows to overwrite files outside the safe-path. I've been thinking to deny writes with a hard link count of more than one to prevent this from happening. You can prevent this for now, by making sure the DESTDIR is always empty.
This faking seems to trigger bugs in other software. I've come across some problems that were caused by applications that assumed too much and checked too little. Resulting in a segfault.
This will make sure that programs will work as they should in all conditions and it is still safe. Additionally, you could diff between the original files and your 'redirected-root'.
This however is far more complex than what soapbox represents at the moment. And maybe should be considered for a seperate project.
rpm2cpio soapbox-0.3.1-0.dag.src.rpm | cpio -i *.tar.bz2
By common request:
Soapbox is only useful under certain conditions (how it is implemented now), where writes are considered critical. But in some cases reads can be considered critical too. And maybe you want to allow reads from one dir and writes to another dir. So you have to be able a per directory and a per file basis configuration. Especially when you want to return EACCES for one file and succesful for another.
That's where I want to go. An apache-style configfile that is defined in environment variable SOAPBOX and that will allow you to configure the default behaviour and specific file and directory behaviours.
Ideally, people could create a /etc/soapbox/proftpd.conf containing:
and change their /etc/init.d/proftpd to contain:Deny: reads writes DenyError: EACCES Logfile: /var/log/soapbox/proftpd.log <File /etc/proftpd.conf> Allow: reads </Directory> <File /var/log/xferlog> Allow: writes </Directory> <Directory /var/ftp> Allow: reads </Directory> <Directory /var/ftp/incoming> Allow: writes </Directory>