HOWTO chroot jail
The chroot command isn't all that useful in most situations. Some may not of even heard of it or ever used it. This article explains one of the, if not the most common, use of chroot.
The chroot jail is a very basic concept to grasp. The idea to it is that in order to prevent harm to an environment, you simulate the environment in a way that prevents harm to the original environment. This is useful when using software that you don't trust or to simulate an environment while testing software that may or may not require heightened privileges. You do this by changing the lower most region accessible during a given session, generally using chroot on a Linux system (given the name, "chroot jail"). I'll make a small example to help image what I'm talking about on a general Linux system.
[root@caedo jail]# ls /
bin cgroup etc jail lost+found mnt proc run selinux sys usr
boot dev home lib media opt root sbin srv tmp var
This is your general structure of a Linux directory structure, taken from my computer, not including the subdirectories. Let's say we have a malicious program that might go crazy and attempt to break things. Well, you generally don't want to use a program as such any ways but in the case that you need to or you are testing software, we can reduce the damage done to almost none by using our chroot jail. All a chroot jail really is is a minimal environment in which the program can run. You literally copy (not link) to any libraries and resources that are required for the program to run.
For a real example, I'll chroot jail the program "cat" (which will be referred to as "the program" to prevent confusion) since it's crazy and can force my computer to explode (not really, just an example).
Contents |
We need to know what libraries the program uses if any. We can find out by using the program 'ldd'. This lists expected shared libraries to be loaded on startup. Dynamically loaded library can have dependencies of their own which may not be listed with this tool and you must take caution of. Dedication and tools such as Jailkit can simplify this task (however the tools may not do the most perfect job). Output of my bash for Fedora would be something like:
linux-gate.so.1 => (0x00aae000)
libc.so.6 => /lib/libc.so.6 (0x4653a000)
/lib/ld-linux.so.2 (0x46519000)
Tracking Other Things
Figure out other things the library requires. For instance, if it requires a configuration file from /etc or perhaps it may need /dev/null. 'cat' is a very simple program. It needs no configuration or external files that I know of. I chose 'cat' for the very purpose of keeping the example simple for now. If your program requires such a configuration file, just mark it down as something it needs and hold on to that reference, we'll use it later. Each program may vary and there is no universal method of finding such things.
Setting Up a Directory Structure
The whole point of a chroot jail is to mimic the original environment. To do this, we need to copy the original environments' structure into a directory that we'll later chroot into. This can be anywhere. For now, I'll have the directory be in '/jail' which will be owned by root:root for simplicity. Inside of /jail, we'll just create the directories required to run cat. The minimalistic structure would have nothing but lib. This is the case in quite a few. Some may be able to use basic configuration files in /etc (such as bashrc for bash), however, these files are generally *not needed*. If you want though, you can add an etc directory to your jail and add a configuration file if you wish.
Some applications that use the network are a bit more complicated. They need the necessary configuration to access the internet. A lot of the time, an application can run without these. However, if your network requires some special setup, you might need a file such as /etc/hosts or /etc/networks. You may physically copy these files from the original environment to the jail with no harm.
Here's what my directory looks like in the end:
[root@caedo jail]# ls /jail/**
/jail/testfile
/jail/bin:
cat
/jail/lib:
ld-2.14.so ld-linux.so.2 libc.so.6
NOTE: It doesn't matter where the target executable is really. As long as you know where it is relative to the new root.
Be aware that libraries are often linked to more specifically versioned binaries. For instance, ld-linux.so.6 actually links to ld-2.14.so. Because of this, you must be sure that you preserve the file rights when copying from the original environment and to copy what it links to. linux-gate isn't included since it doesn't exist. I don't remember how that works exactly...
Chrooting Into the Environment
If you've tried chroot into /jail, you'll probably get a message along the lines of "chroot: failed to run command `/bin/bash': No such file or directory". This is to be expected. chroot the command expects the new root environment to have a couch and television prepared when it gets there (actually, what it wants is a shell in /bin/bash). This is troublesome and we may not want our new environment to have a bash shell at all. This is actually easy to fix. In our example, a command such as 'chroot /jail cat' would work. This changes directory and then executes the command relative to the new path. If we add a new file named testfile that contains something like "LOLOLOLOLOLOLOLOLOL", we can pass in the argument to output the file's contents as such: 'chroot /jail cat testfile'.
Security Measures
If your purpose for a jail environment is to stop a program from being malicious with heightened privileges, it's not suggested unless you are sure of what it does. You can get out of a chrooted environment as root. When you want to use a program without privileges (such as a basic user), you can switch the user and group permissions after chrooting into the environment. The chroot command takes an argument to fix this. The following is an example: 'chroot --userspec=500:500 /jail cat testfile' 500 is the UID and GID corresponding in /etc/passwd (not needed in the chroot environment). It can also take the group and user name if I'm not mistaken.
Coding Examples
I'm not going to give a direct example. However, strace provides the very straight forward process of how to go about it:
chroot("/jail") = 0
chdir("/") = 0
setgid32(500) = 0
setuid32(500) = 0
execve("/usr/lib/ccache/cat", ["cat", "testfile"], [/* 53 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/local/bin/cat", ["cat", "testfile"], [/* 53 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/bin/cat", ["cat", "testfile"], [/* 53 vars */]) = -1 ENOENT (No such file or directory)
execve("/bin/cat", ["cat", "testfile"], [/* 53 vars */]) = 0
Really. It's as simple as that. Also, note the call to chdir. This is to make sure the directory had changed (as this used to be a security issue). The call to setuid and setgid might vary (specifically, it probably won't have 32 in it).