Local Security: chroot

A chroot jail is a technology used to change the "apparent root / directory for a user or a process" and confine that user to that location on the system. A user or process that is confined to the chroot jail cannot easily see or access the rest of the file system and will have limited access to the binaries (executables/apps/utilities) on the system. From its man page:

chroot (8) - run command or interactive shell with special root directory

Although it is not security proof, it does have some useful security use cases, from tampering. Some have used chroot to contain DNS servers, for example.

chroot is also the conceptual basis for some kinds of virtualization technologies that are common today, like Docker.

chroot a current user

In this tutorial, we are going to create a chroot for a human user account.

Step 1: Let's create a new user. After we create the new user, we will chroot that user going forward.

sudo su
useradd -m -U -s /usr/bin/bash vader
passwd vader

Step 2: Next, we chroot vader into a new directory. That directory will be located at /var/chroot. Note that the root directory for our regular users is /, but user vader's root directory will be different /var/chroot, even if they can't tell.

mkdir /var/chroot

Step 3: Now we set up available binaries for the user. We'll only allow bash for now. To do that, we'll create a bin/ directory, and copy bash to that directory.

which bash
mkdir -p /var/chroot/usr/bin
mkdir -p /var/chroot/bin
cp /usr/bin/bash /var/chroot/usr/bin/
cp /usr/bin/bash /var/chroot/bin/

Step 4: Large software applications have dependencies (aka, libraries). Thus, next we copy the libraries that bash needs to run.

To identify libraries needed by bash:

ldd /usr/bin/bash

Use the locate command to be sure you identify the exact locations of the libraries:

locate libtinfo.so.6

Create a library directory. We'll name the library directory after lib64 since these are all lib64 libraries.

mkdir /var/chroot/lib64
cp /usr/lib64/libtinfo.so.6 /var/chroot/lib64/
cp /usr/lib64/libdl.so.2 /var/chroot/lib64/
cp /usr/lib64/libc.so.6 /var/chroot/lib64/
cp /usr/lib64/ld-linux-x86-64.so.2 /var/chroot/lib64/

Step 5: Create and test the chroot

chroot /var/chroot/
bash-5.1# ls
bash: ls: command not found
bash-5.1# help
bash-5.1# dirs
bash-5.1# cd bin/
bash-5.1# dirs
bash-5.1# cd ../lib64/
bash-5.1# dirs
bash-5.1# cd ..
bash-5.1# exit

Step 6: Create a new group called chrootjail. We can add users to this group that we want to jail. Instructions are based on linuxconfig.org.

groupadd chrootjail
usermod -a -G chrootjail vader
groups vader

Step 7: Edit /etc/ssh/sshd_config to direct users in the chrootjail group to the chroot directory. Add the following line at the end of the file. Then restart ssh server.

# nano /etc/ssh/sshd_config
Match group chrootjail
            ChrootDirectory /var/chroot/

Exit nano, and restart ssh:

systemctl restart sshd

The logout of the server altogether:


Step 8: Test ssh.

Connect to the Fedora server via ssh as the user vader:

ssh vader@relevant_ip_address
-bash-5.1$ ls
-bash: ls: command not found

That works as expected. The user vader is now restricted to a special directory and has limited access to the system or to any utilities on that system.


By using the ldd command, you can add additional binaries for this user. As an exercise, use the ldd command to locate the libraries for the nano editor, and make nano available to the user vader in the chrooted directory.

Nano in chroot

After making Bash available in chroot:

(Side note: Unlike previous instances when I use the # sign to indicate a comment, below I'm using the # sign below to indicate the root prompt.)

# which nano
# cp /usr/bin/nano /var/chroot/bin/
# ldd /usr/bin/nano
linux-vdso.so.1 (0x00007fff5bdd5000)
  libmagic.so.1 => /lib64/libmagic.so.1 (0x00007f0ce11a7000)
  libncursesw.so.6 => /lib64/libncursesw.so.6 (0x00007f0ce1167000)
  libtinfo.so.6 => /lib64/libtinfo.so.6 (0x00007f0ce1138000)
  libc.so.6 => /lib64/libc.so.6 (0x00007f0ce0f6e000)
  libz.so.1 => /lib64/libz.so.1 (0x00007f0ce0f54000)
  libdl.so.2 => /lib64/libdl.so.2 (0x00007f0ce0f4d000)
  /lib64/ld-linux-x86-64.so.2 (0x00007f0ce1232000)
# cp /usr/lib64/libmagic.so.1 /var/chroot/lib64/
# cp /usr/lib64/libncursesw.so.6 /var/chroot/lib64/
# cp /usr/lib64/libtinfo.so.6 /var/chroot/lib64/
# cp /usr/lib64/libc.so.6 /var/chroot/lib64/
# cp /usr/lib64/libz.so.1 /var/chroot/lib64/
# cp /usr/lib64/libdl.so.2 /var/chroot/lib64/
# cp /usr/lib64/ld-linux-x86-64.so.2 /var/chroot/lib64/
# chroot /var/chroot/
bash-5.1# nano
Error opening terminal: xterm-256color.
bash-5.1# exit

To fix this, install ncurses-term and copy over additional files:

# dnf install -y ncurses-term
# locate xterm-256color
# mkdir -p /var/chroot/etc/terminfo/x/
# cp /usr/share/terminfo/x/* /var/chroot/etc/terminfo/x/
# chroot /var/chroot
# nano