Sandboxing: Chroot Sandbox

Sandboxing: Chroot Sandbox

This is the third installment on a series of various sandboxing techniques that I’ve used in my own code to restrict an applications capabilities. You can find a shorter overview of these techniques here. This article will be discussing Chroot sandboxing.

Intro To Chroot:

If you’ve been on Linux for a little while you may have already heard of a chroot. Maybe some service you use “chroots” itself. You may have also heard that chroot’ing isn’t great for security, or maybe even that they’re super easy to break out of. Whoever said that isn’t wrong, chroot environments can be great for confining some things and really awful for confining others.

Chroot is, simply, “change root”. The Linux file system has a root, it’s “/” – everything is an offset from this root node. But with chroot you can tell a process that “/” is actually somewhere else. Now, as far as that process knows, the entire filesystem begins somewhere else.

There are two requirements for a process to be able to break out of a chroot environment:

1) The ability to call chroot() again (this requires root, or CAP_SYS_CHROOT)

2) The ability to write to the chroot environment.

So, as soon as you chroot, your process should drop privileges and lose the CAP_SYS_CHROOT capability. If you can remove write access, all the better.

In the case of SyslogParse I did both.

The Code:

mkdir("/tmp/syslogparse/", 400);

chdir("/tmp/syslogparse/");

if(chroot("/tmp/syslogparse/") != 0)
err(0, "chroot failed");

Line by line:


mkdir("/tmp/syslogparse/", 400);

mkdir() is a system call that makes a directory at the specified path, with the specified permissions.

In this case the code is creating a directory /tmp/syslogparse/ and only root can read the folder, and no one can write to it.


chdir("/tmp/syslogparse/");

We move our working directory to the folder we’ve just created.


if(chroot("/tmp/syslogparse/") != 0)
err(0, "chroot failed");

chroot changes the root directory to the folder we’ve just created. Now the program, as far as it knows, is at “/” – the root directory. It only sees an empty file system, none of which it can write to.

The next step here is to drop permissions with setUID() and setGID(), which I’ll be going over in the next article.

Conclusion:

At this point the chroot *can* be broken out of. Nothing is stopping this program from simply changing the mode of the folder to allow writing to it. If, however, you drop privileges (again, see next article), you’ll be in a chroot that can not be bypassed by any design flaws in the chroot itself.

The benefits of being in a no-write chroot are quite nice. The process can’t write any files, which means it can’t open any pipes to other processes – no communication.

With a Grsecurity kernel (some distros package these particular chroot modifications) there’s a host of other restrictions applied, chroot sort of acts as a separate namespace/ user, and communicating outside of the chroot in any new way is denied. The process is isolated more strictly.

It’s a very nice way to sandbox an application, and it’s fairly simple, though not suitable for all applications.

Next Up: Limited Users

Leave a Reply

Your email address will not be published. Required fields are marked *