Aaron Poffenberger

There are a great many ways that crackers attempt to subvert the security of a computer. For servers one of the most popular is to cause a buffer overflow.

As most computer users know, computers store data in memory. When programs need to store data in memory they ask the operating system for a block of memory – a buffer – to store it in. A buffer-overflow attack occurs when an entity forces the program to write more data into memory than the operating system allocated.

This might not seem all that harmful but we have to keep in mind that programs are also data, a special kind of data that tells the computer what to do. If an attacker can force one program to write programming instructions into memory the computer will later execute, then the attacker can tell the computer what to do — including telling the computer to run an interactive shell. Since computer services often run as the root user, compromising a service can give an attacker full control of the server. Even those services that don't run as root pose a risk if an attacker can gain access to them. One compromised account can provide venues for attacking other, more valuable systems within the network.

There are several ways programmers can try to prevent buffer overflows but it only takes one missed hole for an attacker to take control of a server. The first step before selecting chroot(8) is to try and reduce the privileges a program or system service runs under. Rather than root, many services on OpenBSD run as user "daemon" or as a user named after the service such as "_mysql". Still, if an attacker should successfully overflow a program buffer and get an interactive shell it would be nice if there were a way to "lock" the user in a jail where it can't cause much harm. Enter chroot(8).

chroot [-g group,group,…] [-u user] newroot [command] The chroot command changes its root directory to the supplied directory newroot and executes command, if supplied, or an interactive copy of the user's shell.

On Unix-like operating systems there is one unified directory tree rooted under ''. Common sub-directories under '' are '/bin', '/etc' and '/var'. This unified directory tree is both a boon and a possible problem. Users, programmers and system crackers all know that the path to any file begins with '/'. On many systems there will be a shell program at '/bin/sh'. With chroot, however, we can start the running program in a directory anywhere on the system and tell that program that the directory-tree root starts there.

Example:

Log into your OpenBSD system. Change directory to '/tmp'. Make a temporary test directory. Change directory to the new test directory. Now copy the contents of '/bin' to the directory. Here are the steps from the command line:

$ cd /tmp $ mkdir test $ cd test $ cp -pR bin .

With this setup we can test the chroot. Create a chroot(8) by typing:

$ chroot /tmp/test /bin/sh

It's very important any time you create a chroot(8) that the path to the command you pass in exists in the chroot environment itself. chroot(8) first creates the new root environment and then calls the command. That's why we didn't type `/tmp/test/bin/sh`. Note also that we're not running the sh(1) command from the original root environment. To test that, try running a command that would normally work, like `man sh`:

/bin/sh: man: not found

You get an error because man(1) is found in '/usr/bin'. Your chroot(8) environment doesn't have a '/usr/bin' directory. In fact, it has no directories other than '/bin':

total 12 drwxr-xr-x 3 1000 0 512 Nov 3 05:35 . drwxr-xr-x 3 1000 0 512 Nov 3 05:35 .. drwxr-xr-x 2 1000 0 1024 Dec 30 2008 bin

There are plenty of commands you can run, ls(1) for example, but that's because it's in the '/bin' directory:

-r-xr-xr-x 1 1000 0 82636 Dec 30 2008 /bin/ln -r-xr-xr-x 1 1000 0 180940 Dec 30 2008 /bin/ls

Look back at the `ls -l /var/www` command from before. There's no '/bin' directory. Suppose an attacker managed to exploit a hole in Apache. There's no shell command. There's no '/bin' directory. There's little more than logs and files. By running Apache in a chroot(8) the OpenBSD developers have ensured that this popular service is protected from exploitation should an attacker manage to get find a vulnerability.

Careful application of chroot(8) is one of the many reasons OpenBSD is described as "Secure by Default".