DAG

Shortcuts:
Dconf ∑ Dstat ∑ Dwall ∑ Dweb ∑ Dwscan ∑ Lyrics ∑ mrepo ∑ Pixies.. ∑ RPMs ∑ unoconv ∑ wascii ∑ wiipresent ∑ Yam ∑

Google Site Search:
Flemish symbol European symbol
» Dag Wieers » Home-made » Soapbox - Restrict processes from tampering with files. 
Soapbox - Restrict processes from tampering with files.
Soapbox allows to restrict processes to write only to those places you want. Read-access however is still based on file-permissions. By preloading the Soapbox library, you can run programs as root and monitor which writes/changes are made, without them really happening. (Typically 'make install')

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.
It sounds like a sandbox, it feels like a sandbox and it might even be a sandbox. But the eye sees a, uhm, soapbox :)

According to the Jargon File, 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:
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>.
Here's a simple, but straight-forward example:
# 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
So I open up /tmp for compilation: (In this case I could have allowed only eg. /tmp/cc)
# 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).
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:/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
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').

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 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.

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: Extracting a tarball by doing:
rpm2cpio soapbox-0.3.1-0.dag.src.rpm | cpio -i *.tar.bz2

By common request:

Maybe the following idea will live as a side project (Cerealbox?), because it will make and end to the easy of use of soapbox as it is now ;)

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:

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>
and change their /etc/init.d/proftpd to contain:
LD_PRELOAD="/lib/soapbox.so" SOAPBOX="/etc/soapbox/proftpd.conf"