Creating a Chroot on OpenBSD



Chroots have many uses in UNIX-like operating systems and the chroot(8) command is not unique to OpenBSD. They are often used to improve security in order to run a potentially vulnerable service in its own environment so that if it becomes compromised and an attacker manages to escalate their privileges to that of the compromised service, they are still constrained to the chroot that the service has been run in.

For my uses, chroots are great for creating small sandbox instances of an operating system where I can muck about, compile and install software or build and test OpenBSD ports. When I am done, I can simply wipe the chroot away and replace it with another fresh one. They effectively perform the same task as virtual machines but do not produce the same overhead of an entire operating system.

It is easy to create a chroot in OpenBSD. The following steps outline the process and by the end you should have a fully up and running instance of OpenBSD to be utilized in any way you choose.


The first thing to do is decide where you want to store your created chroots within your system. This is important because if this is on an existing partition, the mount flags need to be changed within /etc/fstab so that nosuid and nodev are not set. This has a few security considerations and so it is much better to create a new partition and dedicate it entirely to chroots. These flags need to be removed since the chroot will need to be able to create device nodes and suid binaries on the partition for correct operation.

I am storing my chroots in /jails (a separate partition I created during installation) so my /etc/fstab file needed to be modified as follows:

814fb7ccfd84e045.l /jails ffs rw,nodev,nosuid 1 2

Should become:

814fb7ccfd84e045.l /jails ffs rw 1 2

Now that the partition is set and has been remounted with the new flags (an easy way to do this is by just restarting the machine), I create a new folder in it which will contain the new chroot. Since my intended use for it is often to function as a build sandbox, I will call mine sandbox.

# cd /jails
# mkdir sandbox
# cd sandbox

Now we want to construct the base file layout for OpenBSD. This is where using an operating system with simple base packages makes this easier since we do not need to rely on a package manager for this step. Instead we simply extract the small number of archives containing the entire base system. These files are found on the OpenBSD FTP or on the install CD so we mount the CD with the following commands

# mount -t cd9660 /dev/cd0a /mnt

And then we extract them into our current location (the sandbox directory). I also suggest copying these archives to your hard disk for future chroot setups.

# tar -xzf /mnt/5.5/i386/base55.tgz
# tar -xzf /mnt/5.5/i386/etc55.tgz
# tar -xzf /mnt/5.5/i386/comp55.tgz
# tar -xzf /mnt/5.5/i386/xbase55.tgz
# tar -xzf /mnt/5.5/i386/xshare55.tgz
# tar -xzf /mnt/5.5/i386/xetc55.tgz
# tar -xzf /mnt/5.5/i386/xfont55.tgz
# tar -xzf /mnt/5.5/i386/xserv55.tgz

Note that I also extracted the Xenocara (x*.tar.gz) packages. This is because OpenBSD recommends always installing them as part of base even if they are not used. Since I intend to build software in the chroot, I also needed them otherwise the ports system requires additional steps to get working.

At this point I also download and extract the ports tarball. This is optional depending on what you intend to do with the chroot.

# cd usr
# ftp
# tar -xzf ports.tar.gz
# cd ..

In order for the programs in the chroot to work properly, it needs the /dev folder to be populated. You will notice that the MAKEDEV script has been extracted as part of the base. All we need to do is run it like so.

# cd dev
# ./MAKEDEV all
# cd ..

Once this is done, I copy across the /etc/resolv.conf file from the host so that I can correctly resolve DNS entries from within the chroot.

# cp /etc/resolv.conf etc/

We will finally use the chroot command to call ldconfig within sandbox so to ensure that the /var/run/ file is correctly generated. This is required so that any program that we run in the chroot that utilizes a shared library will be able to find it.

# chroot /jails/sandbox ldconfig /usr/lib /usr/local/lib /usr/X11R6/lib

Now we are ready to use the chroot command again to actually enter the newly created instance. I also specify su -l so that the correct environment is set for the superuser of that chroot.

# chroot /jails/sandbox su -l

Congratulations, the chroot is now set up and ready for use. If you plan on using it to build ports, then you can immediately start doing so as follows.

# cd /usr/ports/net/curl
# make package clean

From here, you can do a lot of damage without adversely effecting the host install. Be aware though that it is possible for a malicious user or program to break out of this setup. This is quite unlikely to happen for my purposes but if you are concerned about this, you might want to look into similar alternatives such as Jails on FreeBSD, Zones on Solaris and WPARs on AIX.


One thing that you may find useful is to script the above setup steps. This will allow you to potentially setup and tear down chroots quickly as needed. Luckily almost all the steps (apart from perhaps setting up the partitions) are very straight forward to add to a shell script.

Another thing to note is that OpenBSD comes with Xephyr as part of the base system. This tool makes it very easy to run X11 applications from within the chroot. Once Xephyr is running, executing the following command from within the chroot should open up an xterm within the Xephyr window.

$ DISPLAY=:1 xterm

I hope you have found this brief startup guide on how to setup a chroot useful. Please feel free to leave a comment if you notice anything to be incorrect or if you are running into any problems that you would like me to cover.