Yet another “How to Chroot” article

There are loads of “how to set up chroot” guides out there, and this is yet another one as I had to piece together quite a few to get things to work they way I needed them to and to my liking. So as I need to make notes for when I inevitably need to set this up again I figure I may as well share those notes. Hopefully this well be a suitably idiot guide. This is written for a Ubuntu system so on other systems your mileage may vary.

The basics

I’m going to break this down to the first steps that are vital for getting any chroot jail to work and then look at making it useful. But even these basic steps could probably be made even more minimal if you really wanted to.

For the purpose of these notes just assume that every command is either done as root or prefixed with sudo also that unless explicitly stated that the chroot directory is the working directory.

Create the basic directories

First create the directory that will be the root of your chroot jail:
mkdir /home/chroot
Within that directory create directories for dev, etc, bin and tmp and also vitally lib/x86_64-linux-gnu
mkdir -p dev etc tmp lib/x86_64-linux-gnu
That’s the basic structure that’s needed to do pretty much anything, other directories will be created later as needed.

Having created our basic directory structure we can start to populate it with the files we just can’t live with. The idea here is to create as little as possible as the less there is in the jail the less there is to abuse.

Populate $chroot/dev

Next up populate devchange into your newly createddev directory and:

  • mknod -m 666 null c 1 3
  • mknod -m 666 ptmx c 5 2
  • mknod ram c 1 1
  • mknod -m 444 random c 1 8
  • mknod systty c 4 0
  • mknod -m 666 tty c 5 0
  • mknod tty1 c 4 1
  • mknod tty2 c 4 2
  • mknod tty3 c 4 3
  • mknod tty4 c 4 4
  • mknod urandom c 1 9
  • mknod -m 666 zero c 1 5
  • mkdir pts
  • mkdir shm

You quite possibly don’t need all of those, but null, random and urandom are almost certainly required.

The final vital files

Now to add a few things to our new etc directory, as ever depending on what you want to do with your chroot jail may not need this much – add only the bare minimum you need.

  • grep ^root /etc/passwd > passwd
  • grep ^user /etc/passwd >> passwd

One further file has to be copied into our chroot jail before you can even think about testing things. The file libnss_files.so.2 is required to look verify the chrooted user in the minimal /etc/passwd file.
cp /lib/x86_64-linux-gnu/libnss_files.so.2 /home/chroot/lib/x86_64-linux-gnu/ libnss_files.so.2
Now that’s in place we can test the chroot environment:
chroot --userspec=user /home/chroot/
chroot: failed to run command /bin/bash : No such file or directory

Predictably things didn’t work, as we have no executables that can be run in the chroot jail. What executables and other files you need to add depend very much on what you want to do. I was creating a minimalist user environment so that will be my example.

Making it useful

Populating $chroot/etc

First a few more things in etc:

  • cp /etc/resolv.conf ./
  • cp /etc/localtime ./
  • cp /etc/hosts ./
  • cp /etc/mailcap ./
  • cp /etc/mime.types ./

Create a profile of some sort in etc to reflect what you want to do, at the very least you want to set the path. Depending on how restricted your environment and how much hassle you can live with – you could make this a non-standard path to obscure things a bit and make it harder for people to guess at things. However due to the assumptions that many many programs make you’ll almost certainly need a /bin directory containing sh. For the purposes of this example I’m going to assume almost everything gets dumped in bin.

This is where you need to determine what the minimum set of commands are that you want to make available. You also want to make sure there’s nothing that is too handy for breaking out of the jail, so really avoid anything setuid or setgid.

For my particular needs I want to mainly use ksh and a few other utilities so I copied the following into bin

  • ksh
  • pdmenu
  • date
  • logger

I actually have a few more bits installed but those will do by way of example.

Given the problems that arise from a lack of /bin/sh I created a symlink from ksh to sh and to provide a restricted shell also to rksh.

Now as I didn’t recompile all of those as static binaries they won’t work without also copying across the relevant libraries so time to run ldd against each one and see what’s needed.
e.g.
ldd ksh
linux-vdso.so.1 => (0x00007fff1dbfe000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f965857f000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6
/lib64/ld-linux-x86-64.so.2 (0x00007f9658a92000)

So I can now copy the referenced libraries into the same place my chroot jail
cp /lib/x86_64-linux-gnu/libdl.so.2 /home/chroot/lib/x86_64-linux-gnu/libdl.so.2
Copy in each library, and then run ldd on the next program and repeat. There are scripts out there that makes this easier, but it’s good to understand how it actually works.

Final steps

That’s pretty much it, depending on what the purpose of your chroot is and who’ll be using it. In my case I need for what has to be considered a hostile environment (the Internet), so I want to tighten things up a bit further.

To make life a bit better I created a home directory for the chrooted user, but then change the ownership and all write permissions. All the profile and rcfiles were created outside of the home directory and symlinks created for them. Every file and directory which didn’t need to be writable was made read only ( so everything but tmp and dev ).

With all that done I added the chroot option to my SSHD config and let people in.
ChrootDirectory chroot
That is of course all well and good if you’re using SSH, if you’re using something else such as telnetdthat relies on say /etc/pam.d/login then you’ll need to configure pam_chroot. Thankfully this is also surprisingly easy. Just edit the relevant PAM configuration file ( let’s assume login ) to add the line:
session required pam_chroot.so
in the relevant place. Then create or edit the file etc/security/chroot.conf to add the user to be chrooted and where their jail is. The JailKit page goes into more details about this.

Further gotchas

Given that package managers are all the rage these days and often safer than compiling your own. If you want to download and install a package in chroot without breaking your main system. Say maybe a lighter mail server. Then you’ll want to follow these instructions:

  • Download the package .deb file, via whatever mechanism you like.
  • Run the command
    dpkg-deb -x package-name.deb output-directory
  • look in the output directory for the extracted files, find the program file you need.
  • Copy it into the chroot jail and run the ldd process as previously.

Acknowledgements

I looked at far too many pages trying to work out how to set up just the chrooted environment that I needed. However the following were particularly useful:

Bookmark the permalink.

Leave a Reply