Running Software in a chroot

May 19, 2026

The chroot utility runs a process with the given directory set as the root / directory of its filesystem. There are many use cases for such a tool, e.g. to mess around in a Linux system without booting it, to run glibc software on a musl-based host, or to test examples in a fresh sandbox.

This article will not dwell on security concerns: we’ll assume the software we run is not adversiarial. If secure sandboxing is your primary interest, then further measures beyond chroot are necessary to set up a true container, e.g. namespaces and cgroups (see this blog). Containerization software such as Docker automatically manages all these aspects for you.

Warning: A lot of this article assumes that we are working in a fresh sysroot built for the purpose of serving as a chroot jail on the current system. If you instead use the root file system of another Linux install, then it is potentially dangerous to perform operations within the chroot that modify the system.

Table of contents

  1. Setting up a root directory
  2. Sharing kernel drivers and hardware
  3. Network access
  4. Terminal interfaces
  5. Display windows and audio
  6. Full script with cleanup

Setting up a root directory

The easiest way to get a fully functional sysroot is to download a prebuilt archive from a Linux distribution, e.g. the rootfs tarball from Void Linux.

$ mkdir void_sysroot && cd void_syroot
$ wget https://repo-default.voidlinux.org/live/current/void-x86_64-ROOTFS-20250202.tar.xz
$ tar -xpf void-x86_64-ROOTFS-20250202.tar.xz
$ ls
bin   dev  home  lib32  media  opt   root  sbin  tmp  var
boot  etc  lib   lib64  mnt    proc  run   sys   usr
$ cd ..

We should set everything in our sysroot to be owned by the root user.

$ sudo chown -R root:root void_sysroot/*

Now we can simply chroot into a shell.

$ sudo chroot $PWD/void_sysroot /bin/bash
bash-5.3# ls
bin  boot  dev	etc  home  lib	lib32  lib64  media  mnt  opt  proc  root  run	sbin  sys  tmp	usr  var
bash-5.3# ldd /usr/bin/ls
    linux-vdso.so.1 (0x00007e1ab535d000)
    libcap.so.2 => /usr/lib/libcap.so.2 (0x00007e1ab5319000)
    libc.so.6 => /usr/lib/libc.so.6 (0x00007e1ab512f000)
    /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007e1ab535f000

We are inside a Void Linux sysroot and can run the included dynamic binaries with the included program interpreter and dynamic libraries.

Sharing kernel drivers and hardware

Not everything is going to work yet.

bash-5.3# ls /dev/
bash-5.3# ls /sys/
bash-5.3# ls /proc/
bash-5.3# exit

We have no /dev, /sys, or /proc directories! If we ever need to take advantage of drivers or other system files then we are fresh out of luck. This may be desirable if you don’t want to allow such access, but a problem if you want a fully functional sandbox. We can remedy this by binding the relevant filesystems within the sysroot.

$ sudo mount -t proc none $PWD/void_sysroot/proc
$ sudo mount -t sysfs none $PWD/void_sysroot/sys
$ sudo mount -t tmpfs tmpfs $PWD/void_sysroot/tmp
$ sudo mount -t tmpfs tmpfs $PWD/void_sysroot/run
$ sudo mount --rbind --make-rslave /dev $PWD/void_sysroot/dev
$ sudo chroot $PWD/void_sysroot /bin/bash
bash-5.3# ls /sys/
block  bus  class  dev  devices  firmware  fs  hypervisor  kernel  module  power

The combination of --rbind and --make-rslave allows the host to add device nodes to the sysroot, but does not propogate changes to the syroot’s /dev back to the host.

After you finish using your sysroot you should clean up the mount bindings.

bash-5.3# exit
$ umount $PWD/void_sysroot/proc
$ umount $PWD/void_sysroot/sys
$ umount $PWD/void_sysroot/run
$ umount $PWD/void_sysroot/tmp
$ umount -R $PWD/void_sysroot/dev

Network access

Allowing network access is generally as simple as sharing the resolve.conf file from host to guest.

$ cp /etc/resolv.conf $PWD/void_sysroot/etc/resolv.conf

Warning: If you are chroot entering an existing system, not just the sandbox we created, then you should save the the resolv.conf file before overwriting it, and restore it afterwards; see the final bash script.

Terminal interfaces

It’s also often useful to share terminfo to allow TUIs to function correctly.

$ mkdir -p $PWD/void_sysroot/usr/share/terminfo
$ cp -r /usr/share/terminfo/* $PWD/void_sysroot/usr/share/terminfo/

Once again, this is writing into the sysroot here, which is potentially dangerous. It may be a good idea to save and restore the terminfo directory if the given sysroot is not a simple sandbox.

Display windows and audio

Even if you install compatible graphics and/or audio libraries within your sysroot, binaries run within a sysroot won’t be able to interact with the host. E.g. if you install libwayland within a sysroot and your host is running a Wayland compositor, you won’t automatically be able to open Wayland windows from a chroot. Sharing the $XDG_RUNTIME_DIR will allow most applications to work.

$ mkdir -p $PWD/fs$XDG_RUNTIME_DIR
$ mount --bind --make-rslave $XDG_RUNTIME_DIR $PWD/fs$XDG_RUNTIME_DIR

Once again we pass --bind and --make-rslave for one way propogation of changes from host to the sysroot.

Full script with cleanup

The following script performs all of the above setup for a given sysroot directory, then cleans up after the chroot shell exits.

# chroot.sh
#     usage: ./chroot.sh path_to_sysroot

# set up special Linux system directories
mount -t proc none $1/proc
mount -t sysfs none $1/sys
mount -t tmpfs tmpfs $1/tmp
mount -t tmpfs tmpfs $1/run
mount --rbind --make-rslave /dev $1/dev

# share terminfo
mkdir -p $1/usr/share/terminfo
cp -r /usr/share/terminfo/* $1/usr/share/terminfo/

# share XDG_RUNTIME_DIR
mkdir -p $1$XDG_RUNTIME_DIR
mount --bind --make-rslave $XDG_RUNTIME_DIR $1$XDG_RUNTIME_DIR

# share host network config
cp $1/etc/resolv.conf $1/etc/resolv.conf.chroot.old
cp /etc/resolv.conf $1/etc/resolv.conf

chroot $1 /bin/bash

# restore guest network config
mv $1/etc/resolv.conf.chroot.old $1/etc/resolv.conf

# unmount bindings and filesystems
umount $1$XDG_RUNTIME_DIR
umount $1/proc
umount $1/sys
umount $1/run
umount $1/tmp
umount -R $1/dev
Writing Portable C
Aliasing, Arenas, Sanitizers