Sandboxes can be a useful tool for helping protect your system against security compromise, as long as you use it wisely. One sandbox tool in particular, chroot, is simple and easy to use, as well as being available pretty much everywhere Unix is available.

Many application security issues are problems of permissions. Someone gains permission to do things on the computer that you did not want that person to be able to do, and next thing you know, you have been compromised.

Choosing applications that are known, or at least believed, to be more securely designed than alternatives is certainly a fairly effective action to take to assure your system’s security. Another is taking care to configure things properly, so that improper permissions are not made available to people who should not have them. Once all the reasonable steps one can take to secure the application itself have been taken, however, there is still always the possibility that something may go wrong. No matter how diligent you are, there will always be the concern that yours may be the first system on which some malicious security cracker tests a newly discovered vulnerability with a zero-day exploit. That does not, however, mean you have to be unprotected when that happens.

Attempts are always underway to come up with ways to protect ourselves against the unexpected. A strong privilege separation system built into an operating system, such as is the case with typical Unix systems, is an example of this sort of thinking. These protections are not always limited to protection against malicious security crackers; they can also provide protection against bad luck, clueless users, and simple (but perhaps catastrophic) mistakes made by the system administrators, among other things. One approach to securing oneself against the unexpected is that of “sandboxing”.

In application security terms, a sandbox is some technical mechanism by which the operations of some applications may be segregated from the rest of the system in a way that, hopefully, will protect the system against any malevolence or misfortune that may visit those applications.

Virtual machines such as VirtualBox provide a particularly interesting and complete approach to sandboxing, where an entire operating system is loaded into a sandbox that is maintained within another operating system environment. In theory, any applications running within the virtual machine are thus prevented from affecting anything running outside the virtual machine sandbox.

More specialized sandboxes such as Sandboxie also exist, allowing one to run a particular application within a sandbox application.

Most OSes that set out to be an implementation of the Platonic ideal form we know as Unix come with a system call known as chroot() that can be used to create our own sandboxes, essentially on the fly. Some applications are actually designed specifically to call chroot() for themselves when they are started, automatically sandboxing themselves. There is also, however, a chroot command line utility that can be used to access the system call, so that it can be used to sandbox arbitrary applications as needed.

The chroot utility is often the simplest, quickest, and easiest way to sandbox an application — especially a server daemon — where security is a concern. It is also, in many ways, one of the most limited.

When using chroot, a piece of software is started within a sort of false root directory structure, in theory causing the software to be “fooled” into “thinking” there is nothing outside that directory structure, thus insulating the rest of the system from any potentially harmful side-effects of running that software. While any root chrooted process should be prohibited from directly breaking out of its false root directory structure, the potential for some applications to run other software may be leveraged to generate processes that can then break free of the chroot environment. The canonical approach to breaking free of that sandbox is to make use of the ability to remount the current directory.

Considering the limitations of the chroot() system call as a means of sandboxing software must, perforce, be left as an exercise for the reader beyond a particular point. Be very careful about how it is used before relying on it for the security of your system. You should also keep in mind that sandboxes do not secure what they contain, per se; rather, using a sandbox is an attempt to ensure that security failures in a sandboxed application will not be able to affect anything other than the sandboxed environment.

For the following examples, we will assume you wish to run sh, the POSIX standard shell, within a chroot sandbox. Running a shell within anything less than a complete OS emulation when trying to sandbox it is potentially problematic, especially considering that the last thing you want to do when running software within a sandbox created by the chroot() system call for purposes of security is to run it as root, but it serves as a simple example for purposes of explaining how to use the chroot utility. The examples are produced on a FreeBSD 8.0 system; actual output may vary for different systems.

The first thing you need to use chroot to sandbox some application is a directory to use as the false root directory for your application. To do so, just use the mkdir command to create a directory you want to use for that purpose. For instance, you might use the following command to create a directory called false_root within the system’s true root directory:

# mkdir /false_root

Because of the way chroot() works, everything you’ll need to run the sandboxed software needs to be within the false root directory. The obvious first step to satisfying that requirement is to copy the sh executable into your false root directory. First, create a bin directory like the directory where it normally resides on the system, then copy the executable itself into it:

    # mkdir /false_root/bin
# cp /bin/sh /false_root/bin/

Naively, you might try using chroot to run sh now, but it would fail. Nonetheless, we can see how this works (or, rather, does not work) and take a trial-and-error approach to getting it right:

# chroot /false_root/ /bin/sh
ELF interpreter /libexec/ not found

The next step seems to be to make sure you have available:

# mkdir /false_root/libexec
# cp /libexec/ /false_root/libexec/

Then, try again:

# chroot /false_root/ /bin/sh
/libexec/ Shared object "" not found, required by "sh"

“This is getting silly,” you might think. “There has to be a better way to do this than trial-and-error every step of the way.” You would be right: there is a better way. This is where the ldd utility comes into play. It is a tool used to, in the words of the manpage for it, “list dynamic object dependencies”. In other words, it lists all the dynamically linked library dependencies for a piece of software on the system so you can round them all up at once:

# ldd /bin/sh

/bin/sh: => /lib/ (0x280a9000) => /lib/ (0x280be000) => /lib/ (0x280fe000)

# mkdir /false_root/lib

# cp /lib/ /false_root/lib/

# cp /lib/ /false_root/lib/

# cp /lib/ /false_root/lib/

Try chrooting sh again:

# chroot /false_root/ /bin/sh

Eureka! It works. You now have a chrooted sh process running, with the command prompt sitting there waiting for you to enter commands. What shall we use? Maybe ls, to see what is in the current directory:

# ls
ls: not found

Right. There is no ls command within the sh shell itself — it is a separate binary executable utility that has not been copied into the sandbox environment. This sort of very simple, specific operation of the chroot() system call’s sandbox environment allows you to tailor it to your specific needs, leaving out anything that is not actually necessary within your sandbox, thus potentially enhancing security through simplicity.

In practice, the chroot() system call is often used for server daemons that will operate as long-running processes taking requests from outside the system, as a means of protecting the system as a whole from possibly undesirable effects of letting a process run without constant hands-on control by the sysadmin. It is also often used by software developers who need to test certain types of code intended to interact with files stored on the filesystem without endangering actually important files, such as when writing code that generates a lot of temporary files and testing to see if they all get cleaned up properly.

Your uses for it may be your own. As with any security software, it has its specific capabilities, which come with specific limitations, and it should never be treated as a “silver bullet” that can slay the “werewolf” of security compromise — but it can also be used to good effect if used wisely and with full awareness that it is nothing but one more tool in the security toolbox.