According to the , a sandbox is "A controlled environment within which potentially dangerous programs are run.".
It was written to sandbox my RPM build system to prevent pollution of my clean build environments by untrusted Makefiles. Intelligent people would wonder why building package as a user isn't sufficient.
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.
The Soapbox library is accompanied with a program that simplifies its use. Here's the help from the wrapper script:
Here's a simple, but straight-forward example: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 <dag@wieers.com>.
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 is overloading internal glibc functions, typically the filesystem system calls. When calling one of these overloaded functions, it will verify if the source and/or destination paths are part of the 'allowed' SOAPBOXPATH. In case it is, it will use the original system call. If it isn't allowed, it will return 0 (Successful in case of 'warn'), EACCES (Permission denied in case of 'err') or it will halt immediatly returning successful ('halt').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.
Of course, Soapbox has its limitations. Being a preload library has only limited possibilities. It won't intercept actual system-calls and therefor statically compiled programs will just work as if they're not in a soapbox. If you'd like a more generic (and more complex) solution to do this, take a look at , 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.
If you find any of the cornercases that are not implemented/supported or weird behaviour in Soapbox (segfaults, processes acting weird), try to isolate the problem to something simple and send it to me. There are a lot of debug possibilities, so finding the cause is fairly easy.
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.
What I like to implement next is a redirect-option, so that changes made to files will result in a copy made to another filesystem/path. And the changes are made there.
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.
Packages are located at:
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>
LD_PRELOAD="/lib/soapbox.so" SOAPBOX="/etc/soapbox/proftpd.conf"