Chroot Utilities for FreeBSD

Background

I like to run all the externally accessible services on my Internet server in chroot environments. For those unfamiliar with this, chroot is a system call and command in Unix and unix-like operating systems that changes the apparent root of the filesystem from the real root directory to some lower level.

This can enhance security of the machine by limiting what files can be accessed if the chroot'ed application in compromised. In some cases, it can help prevent compromise in the first place, as many compromises rely on some point on the existance of standard files such as /bin/sh, which can be omitted in the chroot environment.

One of the characteristics of the chroot system call is that it is not a fool-proof trap door. That is, if you can call chroot to limit yourself, there are ways to call it again to unlimit yourself. For this reason, use of the chroot call is normally limited to root (the superuser) and programs run within a chroot environment should not be run as root.

The problem with this with the standard chroot utility is that it is difficult to setup programs to run this way. Once you use chroot, you no longer have access to the whole filesystem, so other programs you might want to change the current user id, like 'su', are not available. And you probably don't want to leave a powerful command like su laying around in the chroot directory.

If you approach this the other way, and change user id first, then you're stuck for another reason: you can no longer run chroot, since you are not root. Of course, this could be solved by the use of a setuid copy of chroot, but that's not necessarily a pretty solution, either.

The Solution

What is really needed is a command that performs both operations at once. If it could start the server process up as well, that would be even better!

Some years ago, I wrote a program called 'chrootuid' that does just this. It's called as follows:

chrootuid <new root> <new userid> [ <command line> ... ]

When run, chrootuid first chroots to the specified directory. Then, it changes to the specified user ID (with according groups). Finally, it executes the given command line, much as the shell would. If you don't specify a command, chrootuid tries to run '/bin/sh' (which probably won't work).

The source for chrootuid, chrootuid.c, can be compiled simply with "cc -o chrootuid chrootuid.c".

Even Better

Then, it occurred to me that the solution could be make even better. I run each chrooted application under it's own user ID, so why not take advantage of the user's home directory and shell definitions to eliminate the need for some of the arguments?

The new utility was called 'chrootsu' and did the same function as chrootuid except that the directory to chroot to came from the specified user ID's home directory setting. And the default command to run was the specified user's shell. So:

chrootsu <new userid> [ <command line> ... ]

Of course, you can provide a specific command line to execute instead of taking the default from the user's shell setting. It's also possible to supply just the arguments for the default command, as long as the first one begins with a '-' (hyphen) as most program options do.

Even better, when run, chrootsu checks to see what name it was invoked as. If it is anything other than 'chrootsu', it assumes that is the user ID that is wanted. So the user ID becomes an unneeded argument as well.

The source for chrootsu, chrootsu.c, can be compiled simply with "cc -o chrootsu chrootsu.c".

An Example

On my server, I use the Exim mail transfer agent, which runs under its own user ID and in its own chroot directory. The user's definition in /etc/passwd looks like this:

exim:*:25:25::0:0:Exim Mail Transfer Agent:/var/local/exim:/bin/exim

'exim' is the user ID, the '25's are the user and group number, '/var/local/exim' is the path of the chroot directory, and '/bin/exim' is the default command to run, in this case, the exim program itself.

Now, if I create a link to chrootsu called 'exim' like so:

cd /usr/local/bin
ln -s chrootsu exim

I can run the 'exim' command within the proper chroot directory and under the correct user ID just by typing 'exim'!

So, once this is done, I can start exim in daemon mode to receive incoming mail by simply using 'exim -bd -q5m', the same as I would if it were not run in a chroot environment, with all the chroot and user details taken care of automatically.

Likewise, if I want to see the contents of the mail spool, I can just type 'exim -bp' and again, exim will be executed in the proper chroot directory as the exim user.

Questions or Comments?

If you have questions, comments, or requests on this software, please let me know. I can be emailed at david@madole.net.

I would also enjoy hearing from you if you are using this software.



Web hosting by
Omd3.com Hosting Services
David S. Madole
2003-07-10 2100 GMT