What’s a chroot?
If you try to measure the usefulness of a command, you must take into account the functionality it provides and its ease of use. If it is too complicated for people to use or too long-winded to make them want to try to use it, the functionality might as well be zero. If no one uses it, it doesn’t provide any functionality.
In discussions with Linux users—in person and on forums—it seems that the chroot command is one that is pegged as being difficult to use, or too persnickety and tedious to setup. It seems this terrific utility isn’t used as much as it might be.
With chroot you can set up and run programs or interactive shells such as Bash in an encapsulated filesystem that is prevented from interacting with your regular filesystem. Everything within the chroot environment is penned in and contained. Nothing in the chroot environment can see out past its own, special, root directory without escalating to root privileges. That has earned this type of environment the nickname of a chroot jail. The term “jail” shouldn’t be confused with FreeBSD’s jail command, which creates a chroot environment that is more secure than the usual chroot environment.
But actually, there’s a very straightforward way to use chroot, which we’re going to step through. We’re using regular Linux commands which will work on all distributions. Some Linux distributions have dedicated tools to set up chroot environments, such as debootstrap for Ubuntu, but we’re being distro-agnostic here.
When Should You Use a chroot?
A chroot environment provides functionality similar to that of a virtual machine, but it is a lighter solution. The captive system doesn’t need a hypervisor to be installed and configured, such as VirtualBox or Virtual Machine Manager. Nor does it need to have a kernel installed in the captive system. The captive system shares your existing kernel.
In some senses, chroot environments are closer to containers such as LXC than to virtual machines. They’re lightweight, quick to deploy, and creating and firing one up can be automated. Like containers, one convenient way to configure them is to install just enough of the operating system for you to accomplish what is required. The “what is required” question is answered by looking at how you’re going to use your chroot environment.
Some common uses are:
Software Development and Product Verification. Developers write software and the product verification team (PV) tests it. Sometimes issues are found by PV that can’t be replicated on the developer’s computer. The developer has all sorts of tools and libraries installed on their development computer that the average user—and PV—won’t have. Often, new software that works for the developer but not for others turns out to be using a resource on the developer’s PC that hasn’t been included in the test release of the software. chroot allows the developers to have a plain vanilla captive environment on their computer that they can sheep-dip the software in before giving it to PV. The captive environment can be configured with the bare minimum dependencies that the software requires.
Reducing Development Risk. The developer can create a dedicated development environment so that nothing that happens in it can mess up his actual PC.
Running Deprecated Software. Sometimes you just have to have an old version of something running. If the old software has requirements that would clash or be incompatible with your version of Linux you can chroot an environment for the problem software.
Recovery and Filesystem Upgrades: If a Linux installation becomes inoperable, you can use chroot to mount the damaged filesystem to a mount point on a Live CD. This allows you to work in the damaged system and attempt to fix it as though it were mounted normally at root /. This means the expected file paths within the damaged system will be correctly referenced from the root directory, and not from the mount point of the Live CD. A similar technique was used in the article describing how to migrate the Linux filesystem from ext2 or ext3 to ext4.
Ringfencing Applications. Running an FTP server or other internet-connected appliance inside a chroot environment limits the damage an external attacker can do. This can be a valuable step in hardening the security of your system.
RELATED: How to Migrate Ext2 or Ext3 File Systems to Ext4 on Linux
Creating a chroot Environment
We need a directory to act as the root directory of the chroot environment. So that we have a shorthand way of referring to that directory we’ll create a variable and store the name of the directory in it. Here we’re setting up a variable to store a path to the “testroot” directory. It doesn’t matter if this directory doesn’t exist yet, we’re going to create it soon. If the directory does exist, it should be empty.
If the directory doesn’t exist, we need to create it. We can do that with this command. The -p (parents) option ensures any missing parent directories are created at the same time:
We need to create directories to hold the portions of the operating system our chroot environment will require. We’re going to set up a minimalist Linux environment that uses Bash as the interactive shell. We’ll also include the touch, rm, and ls commands. That will allow us to use all Bash’s built-in commands and touch, rm, and ls. We’ll be able to create, list and remove files, and use Bash. And—in this simple example—that’s all.
List the directories you need to create within the {} brace expansion.
Now we’ll change directory into our new root directory.
Let’s copy the binaries that we need in our minimalist Linux environment from your regular “/bin” directory into our chroot “/bin” directory. The -v (verbose) option makes cp tell us what it is doing as it performs each copy action.
The files are copied in for us:
These binaries will have dependencies. We need to discover what they are and copy those files into our environment as well, otherwise bash, touch, rm, and ls will not be able to function. We need to do this in turn for each of our chosen commands. We’ll do Bash first. The ldd command will list the dependencies for us.
The dependencies are identified and listed in the terminal window:
We need to copy those files into our new environment. Picking the details out of that listing and copying them one at a time is going to be time-consuming and error-prone.
Thankfully, we can semi-automate it. We’ll list the dependencies again, and this time we’ll form a list. Then we’ll loop through the list copying the files.
Here we’re using ldd to list the dependencies and feed the results through a pipe into egrep. Using egrep is the same as using grep with the -E (extended regular expressions) option. The -o (only matching) option restricts the output to the matching parts of lines. We’re looking for matching library files that end in a number [0-9].
We can check the contents of the list using echo:
Now that we have the list, we can step through it with the following loop, copying the files one at a time. We’re using the variable i to step through the list. For each member of the list, we copy the file to our chroot root directory which is the value held in $chr.
The -v (verbose) option causes cp to announce each copy as it performs it. The –parents option ensures any missing parent directories are created in the chroot environment.
And this is the output:
We’ll use that technique to capture the dependencies of each of the other commands. And we’ll use the loop technique to perform the actual copying. The good news is we only need to make a tiny edit to the command that gathers the dependencies.
We can retrieve the command from our command history by hitting the Up Arrow key a few times and then make the edit. The looping copy command doesn’t need to change at all.
Here we’ve used the Up Arrow key to find the command, and we’ve edited it to say touch instead of bash.
We can now repeat the exact same loop command as before:
And our files are copied for us:
We can now edit the list command line for ls:
Again, we’ll use the same loop command. It doesn’t care what files are in the list. It blindly works through the list copying the files for us.
And the dependencies for ls are copied over for us:
We edit the list command line for the last time, making it work for rm:
We use the looping copy command one last time:
The last of our dependencies are copied into our chroot environment. We’re finally ready to use the chroot command. This command sets the root of the chroot environment, and specifies which application to run as the shell.
Our chroot environment is now active. The terminal window prompt has changed, and the interactive shell is the being handled by the bash shell in our environment.
We can try out the commands that we have brought into the environment.
The ls command works as we’d expect when we use it within the environment. When we try to access a directory outside of the environment, the command fails.
We can use touch to create a file, ls to list it, and rm to remove it.
Of course, we can also use the built-in commands that the Bash shell provides. If you type help at the command line, Bash will list them for you.
Use exit to leave the chroot environment:
If you want to remove the chroot environment, you can simply delete it:
This will recursively delete the files and directories in the chroot environment.
Automate for Convenience
If you’re thinking that chroot environments might be useful to you, but they’re a bit fiddly to set up, remember that you can always take the strain and the risk out of repetitive tasks by using aliases, functions, and scripts.
RELATED: How to Create Aliases and Shell Functions on Linux