Creating secure environments with chroot

© Martin Hartinik - 123RF.com

© Martin Hartinik - 123RF.com

Private Prison

Virtualization is fine and all, but sometimes it can be overkill if all you want to do is run a program that you think could pose a threat to your system. chroot jails offer a light, fast, and well-tested alternative.

Some of the riskiest things you can do to your system are run software pulled off the Internet from an unfamiliar site or run applications that have not been tested and that might contain fatal bugs. In either case, it is never advisable to risk your data and hardware by running dubious apps directly on the system you use for your daily work and play.

However, you don't have to give up trying out new software. It could even be a job requirement if you work in IT developing potentially dangerous code – and, let's face it, all experimental code is potentially dangerous. In Linux, you can create a closed and controlled environment to do these things, and that's what chroot is all about.

Personal Space

Using chroot is in some ways similar to virtualizing a system but is much more limited in scope. Instead of recreating an entire computer system, chroot allows you to create a guest shell and an (initially) empty filesystem on a directory of your choice within your own directory tree.

The guest system inherits some of the characteristics of the host system – namely, its kernel and most of its environment variables – but the directory tree disappears, along with all of its commands, shared libraries, device directories, and other resources. Within this clean slate of a system, you create a new filesystem from scratch containing only what you need to run the application you have to test; thus, its name: For all practical effects you are ch anging the root directory location.

Once you have decided where your chroot jail is going to be, you can start copying software over to it to create a secure environment. Owing to the characteristics of this kind of environment, it is highly unlikely that the host system will be affected if anything goes wrong. For example, it is nearly impossible for jailed applications to modify or delete files outside the chroot in the host system. "Nearly" being a key word in the previous sentence.

Building Your Jail

Building a chroot jail is very simple. All you have to do is create a new directory and point chroot to it:

$ mkdir myjail
$ sudo chroot myjail

Note that, although the directory can belong to your own user, chroot can only be run with superuser privileges, hence the sudo at the beginning of the line.

However, entering the previous two lines will only get you an error like:

chroot: failed to run command '/bin/bash':No such file or directory

This happens because the Bash shell is like any other program and, when the system tries to access a shell from within the jail, it doesn't find one and bombs. Thus, your next step is to set up a shell program within your jail.

To do so, the first thing to do is create a bin directory (which is where a Linux system's essential executable programs usually live) in your test directory and copy bash from the host's /bin :

$ mkdir myjail/bin
$ cp bin/bash myjail/bin

You might think that's enough but, if you try chroot again, it will bomb the same as before, because Bash depends on several other files containing code called libraries , which are necessary to make it work. You have to find which ones you need and copy them over to the jail. Note that from within the jail, the rest of the system is invisible, and you cannot access any file from outside, including these all-important libraries.

To find out which libraries Bash needs, you use the ldd command. Its syntax is very simple: All you have to do is pass in the path and name of the application you want to check. In Listing 1, I'm running ldd for Bash, which returns a list of libraries and where they are installed. Notice that most live in a directory called lib64/ , which is hanging off the root (/ ) directory. The 64 indicates that I am using a 64-bit system. If you are using a 32-bit system, the directory will simply be called lib/ .

Listing 1

Libraries on Which Bash Depends

$ ldd /bin/bash
linux-vdso.so.1 (0x00007fff10576000)
libreadline.so.6 => /lib64/libreadline.so.6 (0x00007fa02c744000)
libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007fa02c511000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fa02c30d000)
libc.so.6 => /lib64/libc.so.6 (0x00007fa02bf60000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa02c98c000)

The first item on the list, linux-vdso.so.1 (0x00007fff10576000) , is a virtual library used on some Linux systems, and you can safely ignore it. The rest of the lines point to real libraries that you will have to copy over to a directory with the exact same name in your chroot jail:

$ mkdir myjail/lib64
$ cp /lib64/libreadline.so.6 myjail/lib/
$ cp /lib64/libtinfo.so.5 myjail/lib/
...

… and so on. Once you have copied over all the files, you can test your jail again:

sudo chroot myjail/
Password:
bash-4.2#

Success! The fact that you got a prompt shows that everything is working as it should. However, you will soon come up against some limitations.

Although you can visit the directories /bin and /lib you created in your jail with the cd command and maybe copy and move things around, you can't do much else. You can't even list the contents of the directories (although you can use pwd to see where you are within the directory tree). That's because, whereas cd and pwd are commands integrated within Bash – known as builtin commandsls , the program you use to list directory content, is not.

To be able to use ls , you have to go through a similar process you went through to get Bash working, including copying over all the libraries on which it depends. To begin, exit your jail with:

bash-4.1# exit

then check out Listing 2 to see how it is done. (Your input is in bold.) The list of libraries can vary from system to system.

Listing 2

Making ls Work in Your Jail

01 $ cp /bin/ls myjail/bin/
02 $ ldd /bin/ls
03 linux-vdso.so.1 => (0x00007ffffcb35000)
04 libselinux.so.1 => /lib64/libselinux.so.1 (0x00000036e3c00000)
05 librt.so.1 => /lib64/librt.so.1 (0x00000036e3400000)
06 libcap.so.2 => /lib64/libcap.so.2 (0x00000036ecc00000)
07 libacl.so.1 => /lib64/libacl.so.1 (0x00000036f1400000)
08 libc.so.6 => /lib64/libc.so.6 (0x00000036e1c00000)
09 libdl.so.2 => /lib64/libdl.so.2 (0x00000036e2000000)
10 /lib64/ld-linux-x86-64.so.2 (0x00000036e1800000)
11 libpthread.so.0 => /lib64/libpthread.so.0 (0x00000036e2400000)
12 libattr.so.1 => /lib64/libattr.so.1 (0x00000036ef000000)
13 $ cp /lib64/libselinux.so.1 myjail/lib64/
14 $ cp /lib64/librt.so.1 myjail/lib64/
15 $ cp /lib64/libcap.so.2 myjail/lib64/
16 $ cp /lib64/libacl.so.1 myjail/lib64/
17 $ cp /lib64/libpthread.so.0 myjail/lib64/
18 $ cp /lib64/libattr.so.1 myjail/lib64/
19 $ sudo chroot myjail
20 Password:
21 bash-4.1# ls
22 bin lib64
23 bash-4.1#

Some of the libraries are already in your mijail/lib64 directory, so you can ignore them. Once finished, you'll be able to use ls as you would on the host system.

And that's all there is to it. The process can get much more complicated if you intend to jail more complex programs, so you should check out the box "Running Big Applications," which contains some tips on how to get things working.

Running Big Applications

If you want to run applications that are much more complex than ls in a chroot jail, you'll soon find that there are whole directories you have to include before everything works. What makes things even more difficult is that you might also discover that some of these directories, such as /proc , /dev , and /sys don't even contain real files and subdirectories, but virtual ones.

Files like /dev/sda or /proc/cpuinfo do not point to actual data on the hard disk but are created when the system boots or even while the system is running and cannot be copied or moved. They also cannot be soft-linked with ln -s because, as mentioned elsewhere, the rest of the system beyond the jail is invisible within the jail, so links to files and directories outside the jail show up as broken.

Fortunately, there's a solution to this problem. Using the mount command's -o bind option, you can link directories to your directory and they'll still be available when you run chroot:

$ cd myjail
$ mkdir proc
$ mkdir dev
$ mount -o bind /proc proc
$ mount -o bind /dev dev

A word of warning: Use this method sparingly if your aim is to create an isolated environment: You're opening a great big hole in your jail walls with mount -o bind .