openroot is now called xchroot:

Tux at his computer freebsd devil


chroot for users with Xorg/X11 forwarding and automatic mounting + aufs/unionfs read only root support.

Table of Contents

JavaScript error


Chroot allows you to run commands from a different system installation without having to boot into that system. You do not even need a separate partition for the alternate system installation or root file system. This does of course only work if both systems are Linux installations or both systems are BSD derivates since they will always need a compatible kernel to be in operation. Just shared libraries (*.so, Windows: dll) are loaded from the new root on program invocation out of the chroot environment. Newer kernels use to be backward compatible. Thus chrooting into an elder system installation would always be possible. There are a few exceptions like the old ddrescue program using a deprecated kernel api which is no more supported. Backward compatibility of kernels is also the reason why statically linked programs use to continue to run even without preserving a full chroot environment for them.

Chroot is particularely useful if you have installed more than one Linux distro and want to run programs from another distro than you have actually booted to. Chroot is also widely in use for program development and packaging as it can simulate another environment very well allowing to test on multiple systems at the same time. It can also be used to run programs that are no more available for recent Linux distros.

Chroot works immediately and guarantees minimal effort. You do not have to wait until another system is booted. Memory usage is as little as possible. Under Linux it is possible for a cracker to escape from a chroot environment while chroot-jails are also considered a security feature in FreeBSD.

The only thing you basically have to do in order to change to another chroot environment (i.e. another installed system) is to issue a chroot command as root on the directory that should become the new root of the file system. Use exit to get back to your boot-root.

> chroot /dst/other-linux-system

problems with a pure chroot

Nonetheless you may find out soon that this does not work for many many programs; f.i. you are not able to run any GUI applications as you can not connect to a running X server inside a chroot environment without special provisions even under Linux which allows programs to 'escape' from chroot environments.

For further instructions on how to secure a chroot environment under Linux that does not need X access you may want to have a look at Grsecurity (though booting the system in a virtual machine is the best option for means of security.). Be aware that allowing compromized programs to connect to the same X server (the program that is responsible for graphics output under unixoid systems) together with uncompromized programs will compromize the rest of your system at least as long as no MAC (Mandatory Access System) like SELinux is in place that is able to controlle your X server and adherent programs like DBUS; be it a 'secured' chroot environment or not. We suggest that even with SELinux exploits can likely be used as the X-server is a hard target for confinement. That can be as simple as pasting text into a root console and letting it disappear by appropriate escape sequences fractions of milliseconds thereafter! A more sophisticated attacker will exploit vulnerabilities of your X server. It is an ideal target for exploits as the X server is feature rich and running as root!

There are even more restrictions: you can not run programs such as grub that need access to either /dev, /sys or your /proc filesystem as long as these systems are not mounted properly (i.e. recursively) into the new chroot environment. If you have installed a fresh system and want to access your old installation via xchroot you may want to verify your old installation with a tool like debcheckroot first in order not to infect your new system.

trying to resolve these problems by hand

As far as now you may already know that a pure chroot is very restricted. f.i. You can not run any GUI-applications. A workaround for this is to redirect all Xorg drawing operations through localhost: > xhost +localhost > DISPLAY=localhost:0 chroot /dst/debian;

However this does not work if your X server (being responsible for all graphical output) has been startet with the -nolisten tcp option which is the default now for reasons of security even if you don´t specify that option. You may start an additional X-server with xinit twm -- :1 vt08 -listen tcp for testing purposes. As your primary X-server is usually started automatically by your display manager you would need to configure your display manager to allow tcp access for exploiting this option. Here is a section you can add to your /etc/lightdm/lightdm.conf if you are using lightdm rather than xdm, sddm, kdm or gdm as your display manager:

[SeatDefaults] xserver-allow-tcp=true

Find out about the command line X has been started with by the following command:

> ps ax|grep "X[^/]* " 1959 tty7 Ss+ 75:16 /usr/bin/Xorg -br -nolisten tcp :0 vt7 -auth /var/lib/xdm/authdir/authfiles/A:0-EgqjEQ

You can watch your tcp conncetions on the loopback interface with tcpdump -i lo or wireshark -i lo -k. Note that tcp access is quite a serious security risk if you do not block the respective ports starting from 6000 by your firewall (see netstat -atupn as root). Moreover funneling all traffic via tcp is slow and your X-clients will not be able to make use of shared memory access.

Access to/via localhost is a reason why you may want to allow X access via socket files in your chroot. You will need to mount your socket file /tmp/.X11-unix/X0 to /dst/debian/tmp/.X11-unix/X0. Note that mount --bind does not only work for mount points but also for any other directory like /tmp/.X11-unix or even for files like /proc/cmdline (helpful if you are stuck in your initrd). A proper socat on that file also does the job. Pure symbolic links do not work since a link equals to the character string of the referenced file which points to something different after the chroot. Finally you need a xhost +local: to allow all local clients to connect.

Note that allowing all local clients to connect either via xhost +localhost or xhost +local: is also quite a grave security risk. It means that any user can connect to the X-server. If a daemon or service executes code as some user on your machine that code will have it easy to become root via your X-server (see last section). You can not run sshd on such a machine except if any user that connects via ssh should have unrestricted root rights on your machine. Nonetheless there is also a solution to this problem.

X servers can and usually do use an additional authentication mechanism based on cookies. Keep in mind that cookies are transmitted unencrypted to the X server so that they could be eavesdropped by anyone if transmitted via the local network. Thus you may want to establish an ssh or vpn tunnel whenever you connect to a remote X server in order not to allow any other user access to the same X server who listens on the same net (use ssh -X). Nonetheless this authentication mechanism can be used securely for different users on the same machine and whenever you do only interconnect two machines mutually by a non-eavesdroppable point to point connection.

Now in practice the file that stores the cookie for authentication with the X-server defaults either to ~/.Xauthority or whenever the $XAUTHORITY variable is set then it holds the path and file name of the Xauthority file. The access rights of these files need to be chosen in a way so that other users can not read or write to them. You may simply copy these files though the correct way for adding entries to these files goes via an xauth extract and xauth merge. If you have more than one X-server or sshd running you will likely want to give your chroot only access to your current X-display, not all of them. Copying the file will delete the file in your target chroot which may result in things to stop working there. Consider an sshd in your chroot and a client who connected to it with ssh -X there.

Furthermore we already discuessed programs like grub or gparted that need direct access to your disk devices at /dev. You may simply mirror your /dev to /dst/my-distro/dev in this example before you issue a chroot which can be accomplished by mount --bind /dev /dst/my-distro/dev. Proceed the same way for your /sys and /proc directory which are required by many programs as an additional interface to expose and set kernel data. Note that also subdirectories may require their own mounts as /dev/pts/* for terminals.

All of that is why we want to encourage you to use xchroot instead of tinkering with half brewn solutions as you can find them eleswhere on the web. It will save you from breaking little things and finally it will also save you from quite severe security risks.

xchroot - an extended version of chroot

Simply use xchroot instead to accomplish all these tasks automatically:

> xchroot /dst/debian

In a fact xchroot will do a whole lot more than the minimal provisions we have just discussed. Here is an overview of what xchroot can do for you:

xchroot will mount your new root filesystem and all sub-partitions as for /var /tmp /usr automatically, provided that they are listed in your /etc/fstab (you may want to specify the noauto option if a partition should not be mounted unless an xchroot is issued upon its root.). Mounting an alternative distro not before actually using it may f.i. safe you from unnecessary checkdisks after crashes on bootup or will facilitate the usage of roots on removable media. xchroot will mirror /sys, /proc and /dev and most important it will leverage the usage of GUI applications (DISPLAY=:X). Furthermore unlike with chroot you may specify any program in the chroot environment if you do not just wish to execute the bash standard shell:

> xchroot /dst/debian xterm

xchroot unmounts the helper dirs (sys,proc,dev) automatically on exit independent of the mount state at invocation time. Since version 2.0 it uses furthermore tmp-mirroring by default instead of socat-ing so that socat is no more required. Nonetheless the somewhat more secure -socat option is still available. Socat will definitely be more secure if you choose to run an own X-server for the new chroot enviroment as allowing to connect clients with different privileges to the same X-server is not recommended.

If any program in the chroot is still running on exit you are prompted to terminate it but you can also choose to leave all programs running. In this case you need to quit these programs and umount later on by invoking chroot cleanup with exactly the same parameters as before. If an xchroot is already running a normal chroot should also suffice as long as you terminate the xchroot last. On the contrary there should nothing speak against invoking multiple xchroots leaving the cleanup to the xchroot terminated last (select Leave in the menu.).

xchroot and users: the background

If you have xchroot forget all the other *chroot-s! You do not even need that to chroot as user. If everything is set up correctly run xchroot as user and root alike. Use addsudoers, delsudoers and listsudoers to configure your user setup. More examples can be found in the man page.

root:~> xchroot --dirpfx /dst/ addsudoers elm root:~> xchroot listsudoers xchroot entries in /etc/sudoers: /usr/local/bin/xchroot: elm->elm /dst/* /usr/local/bin/xchroot: elm->elm [-]t /dst/* /usr/local/bin/xchroot: elm->elm cleanup /dst/* /usr/local/bin/xchroot: elm->elm [-]t cleanup /dst/* elm:~> xchroot /dst/debian-32 … elm:~> xchroot -t /dst/debian-32/bin/hostname -- -q localhost

Internally the -u/--user option and sudo implement this: A simple

> xchroot -u usr /dst/debian

will do what you want provided that you execute it as root.
A simple entry in your /etc/sudoers leverages the use directly as user usr:

usr ALL=(root) NOPASSWD: /usr/sbin/xchroot [-]u usr /dst/* usr ALL=(root) NOPASSWD: /usr/sbin/xchroot [-]u usr [-]t /dst/*

letting you open any root under /dst as user usr. (instead of 'ALL' a host name may be stated in case that the /etc/sudoers is distributed to many hosts but should not be allowed on all of them.) You will have to be extremely careful when adding sudoer entries on your own. /etc/sudoers does not use regular expressions but shell pattern globbing which means that an asterisk "*" can stand for any combination of characters including spaces. It thus does usually only make sense to use one star per line at the end in sudoers.

Now we do also want to pass optional parameters to xchroot. Unfortunately we can not put these parameters in front of our root filesystem /dst/* (which stands for 'distribution') because otherwise we could also wildcard our root filesystem specification which is likely not what we want. By this reason the developers of xchroot have invented a little trick: put the -t option in front and put any other option after a '--' at the end right after your root and program specification. The --user option is not allowed in the tail. We will show you by the following example how it works:

elm:~> sudo -E xchroot -u elm -t /dst/debchroot/ -- --unionfs (does not make use of our sudoers entry yet; just have a quick test now.) ----------------------------------------------------------- unionfs -o cow,max_files=32768,allow_other,suid,dev /tmp/xchroot/unionfs-debchroot-13653=RW:/dst/debchroot=RO /tmp/xchroot/mount-debchroot-13653 chroot /tmp/xchroot/mount-debchroot-13653 /tmp/xchroot/startup-13653 Debian GNU/Linux 7 \n \l debian_elm:~> goldendict &

Note that we have used the unsecure -E option which is disallowed by /etc/sudoers which passes all the environment variables along to the new chroot environment. In a fact the only environment variables we need to keep in order for xchroot to function are $DISPLAY, $XAUTHORITY and $XCHROOT_MYROOT. Now let us drop the -E option and merely pass along the variables we need:

elm:~> sudo xchroot -u elm /dst/debchroot/ --env DISPLAY=:0 --env XAUTHORITY=$XAUTHORITY --env XCHROOT_MYROOT=$XCHROOT_MYROOT

That`s it.

Oops?! Haven`t we forgotten about -- before the trailing options and the -t in front? These options are not required as long as you do only use --env as tail option and optionally --noask as the very last option. --noask keeps programs running in the chroot on exit without asking the user whether he/she wants to terminate them. Note that the --user option can not be used as tail option because that would compromize our security needs.

Rather complicated?
I just wanted to show you how xchroot as user works internally so that you can understand why and what it puts into /etc/sudoers.

xchroot and users: user administration commands, tail options

Let us see another example of addsudoers first:

root:~> xchroot --dirpfx /dst/ addsudoers elm adding elm with directory praefix /dst/ to /etc/sudoers ... root:~> xchroot -u elm --dir /dst/debchroot/ addsudoers shell adding elm->shell with directory /dst/debchroot/ to /etc/sudoers ... root:~> xchroot listsudoers xchroot entries in /etc/sudoers: /usr/local/bin/xchroot: elm->elm /dst/* /usr/local/bin/xchroot: elm->elm [-]t /dst/* /usr/local/bin/xchroot: elm->elm cleanup /dst/* /usr/local/bin/xchroot: elm->elm [-]t cleanup /dst/* /usr/local/bin/xchroot: elm->shell /dst/debchroot/ * /usr/local/bin/xchroot: elm->shell [-]t /dst/debchroot/ * /usr/local/bin/xchroot: elm->shell cleanup /dst/debchroot/ * /usr/local/bin/xchroot: elm->shell [-]t cleanup /dst/debchroot/ *

The first addsudoers allows the user elm to xchroot to any directory below /dst/. Note the trailing slash: It is necessary in order not to allow xchrooting to any directory name that starts with /dst. Then we allow the user shell to issue a user-xchroot upon /dst/debchroot and only upon this directory. Host user will be elm. The user in the chroot is shell. This means you need to specify -u shell as you invoke as elm. Finally we list all sudoer entries: addsudoers adds four sudoer entries for every access record: Allowing to invoke xchroot with and without tail opts ([-]t) and finally allowing to issue cleanups for whenever you have invoked xchroot with --noask, killed it or chosen to leave some programs running. Use delsudoers to delete a given group of sudoer entries. You may furthermore remove the lines with [-]t manually to disable tail option parsing for the given user.

Now what is tail option parsing? Tail option parsing allows you to put options at the end rather than letting the options precede your chroot directory and the command to execute in the new chroot. Tail options work like the following: Put the [-]t option in front and all other options at the end after an "--". This has become necessary because of the wildcarding feature of sudoers: A wildcard can stand for any combination of letters. That is why we may only wildcard after specifying user and root filesystem. Have a look at the following examples:

elm:~> xchroot -u shell /dst/debchroot/ elm:~> xchroot -u shell -t /dst/debchroot/ -- --aufs

The first one does not need any option besides -u, the second one needs -t in front because we have -- --aufs at the back. Note that you may add any number of options after the --. Finally I wanna show on how to remove a user spec where 'all' stands for any user with the delsudoers command:

root:~> xchroot --dir /dst/debchroot/ delsudoers all deleting xchroot entries for all->all and /dst/debchroot/ ... 4 lines removed from /etc/sudoers

Now to keep things clear and to see which chroot environment you are currently working in a goodie for colorful user prompts designed especially for use with xchroot (put it in your .bashrc);

export PS1="\[\e[0;32m\]$XCHROOT_NAME${XCHROOT_NAME:+_}\[\e[0;31m\]\u:\[\e[0;33m\]\w> \[\e[0m\]"
elm:~> xchroot /dst/debchroot/
xchroot - visit us on
----------------------------------------------------------- chroot /dst/debchroot /tmp/xchroot/startup-15842 Debian GNU/Linux 7 \n \l debchroot_elm:~> goldendict & ...

xchroot for merely changing the user

xchroot can be used with directory “/” in order to merely change the user but not perform any chroot. This is particularely fast as no mounts are necessary. DISPLAY and XAUTHORITY are forwarded to the new user and a new dbus session is started for the user if none is already running.

root:~> xchroot -u elm --dir / addsudoers bel elm:~> xchroot -u bel / elm:~> xchroot -u bel -t / -- options

Xorg/X11 access as root

Now it may be the case that you have Xorg access by issuing an xchroot but not after a su or sudo su whenever you wanna become root for some purpose. Your distro should normally automatically complete this task by an adequate bash startup. However you can also establish this yourself; a topic which is not directly related to xchroot but which may be very useful in the context of xchroot. The bash environment variable XAUTHORITY points to a file which is by default called ~/.Xauthority and which contains a cookie the client needs to obtain access from the Xorg/X11 server. To move the cookie from /home/usr/.Xauthority to /root/.Xauthority do an xauth extract myfile as user and an xauth merge myfile as root. Myfile may be '-' for stdin/stdout.

Now let the following code in my .bashrc slowly melt on your tongue:

if logname &>/dev/null && [ "$(logname)" != "$(id --name -u )" ] && [ -z "$XCHROOT_MYROOT" ]; then if [ -n "$XAUTH" ]; # matters whether environment variable is unset or empty; not set: should not exist. then sudo -n -u $(logname) env XAUTHORITY="$XAUTH" /usr/bin/xauth extract - $DISPLAY | xauth merge - else sudo -n -u $(logname) /usr/bin/xauth extract - $DISPLAY | xauth merge - fi else if [ -z "$XAUTH" ]; then export XAUTH="$XAUTHORITY" elif [ -z "$XAUTHORITY" ]; then export XAUTHORITY="$XAUTH" fi fi
code sample by Elm.Stb.; usable under GPLv3 or any other license you want.

How to create a chroot environment

You may simply use an old system installation as chroot environment instead of booting into it via qemu-kvm, VMWare or VirtualBox. On the other hand it is not difficult to create an own minimal chroot environment that does only contain the necessary packages to run a certain software or to compile a certain package

In Debian use debootstrap to initialize a new root

> debootstrap lenny /dst/dlenny [] > debootstrap --no-check-gpg --arch=i386 wheezy /dst/dwheezy > sed -i 's#main.*$#main contrib non-free#' /dst/dwheezy/etc/apt/sources.list > xchroot /dst/dwheezy > apt-key list evtl.: > apt-key adv --recv-keys --keyserver XXKEYNRXX > date --set 2014-05-05 > apt-get update > apt-get install locales-all build-essential

For old distributions of Debian the x86_64 arch may not work and you will need to set an elder date since otherwise apt-get update and install will detect an outdated key. This may require you to stop ntp or systemctl stop systemd-timesyncd.service. If the ntp service is called differently at you find out with systemctl -t service | grep time first.

With openSUSE use zypper with the --root option to add repositories and install software:

> mount /dev/sr0 /media/dvd > zypper --root /dst/suse11.2 ar /media/dvd/ dvd or: > zypper --root /dst/openSUSE-tumbleweed ar core-oss see here for all Tumbleweed repos Repository 'dvd' wird hinzugefügt [fertig] Repository 'dvd' erfolgreich hinzugefügt Aktiviert: Ja Autoaktualisierung: Nein URI: dir:///media/dvd > zypper --root /dst/suse11.2 lr # | Alias | Name | Aktiviert | Aktualisieren --+-------+------+-----------+-------------- 1 | dvd | dvd | Ja | Nein > zypper --root /dst/suse11.2 in rpm zypper curl ca-certificates-cacert xterm > xchroot /dst/suse11.2 if necessary: > rpm --rebuilddb

Installing Fedora fromout of Mageia or Debian is also possible: You need the dnf package. In Mageia it is already a system component and for Debian you may simply install it via apt.

> mkdir /dst/fedora36 > wget > wget > wget > rpm -i --root=/dst/fedora36 --nodeps fedora-release-common-36-17.noarch.rpm > rpm -i --root=/dst/fedora36 --nodeps fedora-repos-36-1.noarch.rpm > rpm -i --root=/dst/fedora36 fedora-gpg-keys-36-1.noarch.rpm > rpm -i fedora-gpg-keys-36-1.noarch.rpm > dnf --installroot=/dst/fedora36 --releasever=36 install -y yum which > ls -l /dst/fedora36/etc/resolv.conf lrwxrwxrwx 1 root root 39 Mai 22 17:52 /dst/fedora36/etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf > mkdir /run/systemd/resolve > cp /etc/resolv.conf /run/systemd/resolve/stub-resolv.conf > xchroot /dst/fedora36/

The thing with resolv.conf is a bit tricky. If you have a look it turns out to be a dead link; something that xchroot can not handle on its own since it must not delete the link on chroot. Consider also that according to the default setup /run/systemd is mounted into the rootfs (which is /dst/fedora36). Thus you need to create the file under /run and not under /dst/fedora36/run.

Installing Mageia is similar:

> wget > wget > wget > rpm -i --root=/dst/mageia8/ mageia-repos-keys-8-1.mga8.noarch.rpm mageia-repos-pkgprefs-8-1.mga8.noarch.rpm > rpm -i --root=/dst/mageia8/ --nodeps mageia-repos-8-1.mga8.x86_64.rpm > rpm -ivh mageia-repos-keys-8-1.mga8.noarch.rpm > dnf --installroot=/dst/mageia8/ --releasever=8 install -y mageia-release-Default > dnf --installroot=/dst/mageia8/ --releasever=8 install -y urpmi locales-de [basesystem]

For the purpose of software development you may choose to upgrade to Mageia Cauldron afterwards. This description contains on how to do it for a normal Mageia installation. If you want Cauldron for your chroot, don´t forget to install 'basesystem' (It contains the kernel which you do not need but also some required packages.). Then do the following:

> urpmi.addmedia --distrib --mirrorlist '' > urpmi mageia-repos-cauldron

Here and above, if you need it 32bit then replace 'x86_64' by 'i586'. For productive systems with 2GB or less i586 may be the better choice anyway; it is well maintained. Mirrors can be found here.

Since xchroot v2.7.3/4 minimal xchroots where only busybox is being installed are allowed. Since Debian 11/Bullseye you do not even need the mkdir and touch commands before dpkg -i any more:

> mkdir -p /dst/busybox/var/lib/dpkg > touch /dst/busybox//var/lib/dpkg/status > mkdir /dst/busybox/var/lib/dpkg/updates > mkdir /dst/busybox/var/lib/dpkg/info > dpkg -i --root /dst/busybox/ /media/cdrom/pool/main/b/busybox/busybox-static_1.30.1-4_amd64.deb > pushd /dst/busybox/bin/ > ln -s busybox sh > ln -s busybox grep > ln -s busybox ls > popd

establishing users for a chroot environment

Now before we can use xchroot as user we also need to create these users in the chroot environment. Otherwise they would not be known in the chroot evoking several errors when you tried to chroot as user.

root:~> apt-get install locale-all sudo root:~> grep ^elm: /etc/passwd >>/dst/debchroot/etc/passwd root:~> grep ^elm: /etc/shadow >>/dst/debchroot/etc/shadow root:~> grep ^elm /etc/passwd elm:x:1000:100:Elmar Stelln­berger:/home/elm:/bin/bash root:~> grep 100 /etc/group users:x:100: root:~> grep 100 /dst/debchroot/etc/group root:~> grep 100 /etc/group >>/dst/debchroot/etc/group

If desired you may add additional groups with usermod when xchrooting to the new root.

root:~> usermod --groups audio,lp,video,users,vboxusers elm // resets group membership to exactly these groups root:~> usermod -a -G dialout elm // adds an additional group in addition to current group memberships root:~> grep elm /etc/group video:x:33:gdm,elm vboxusers:x:477:elm

Effective group membership will not change unless you start a new session f.i. by invoking bash or xchroot. Check this with id -a.

xchroot and changeable media

Often you want to mount changeable media in the host system and get them become available in the 'guest' chroot. The -d option carries all mount points under /mnt and /media with it. The -p option additionally looks for mount points under /home. If you want all mounts issued after invoking xchroot to be constantly propagated to the chroot use the -w option for /mnt and /media and -n to additionally include /home. xchroot also allows to specify any directory of desire with -o/--once and -m /mydir1:/mydir2. To mirror mounts from within the chroot to the outside as well as to mirror in both directions see for extended options in the man page (-b,--mirror-out).

chroot applications for the GUI desktop menu

Here is just an example of what xchroot can do:

root:~> xchroot createstartup --command --category Education /dst/deb32/usr/bin/wine /home/data/PCintern/mviewer2.exe /home/data/PCintern/intern.mvb source file: /dst/deb32/usr/bin/wine-stable destination file: /usr/share/applications/intern-deb32.desktop root: /dst/deb32/ xchroot: /usr/local/bin/xchroot root:~> xchroot createstartup --desktop /dst/deb32/usr/share/applications/gimp.desktop source file: /dst/deb32/usr/share/applications/gimp.desktop destination file: /usr/share/applications/gimp-deb32.desktop root: /dst/deb32/ xchroot: /usr/local/bin/xchroot icon: /dst/deb32/usr/share/icons/hicolor/256x256/apps/gimp.png root:~> xchroot createstartup --desktop --category Education ~/.local/share/applications/wine/Programs/Derive\ 5\ Demo/Derive\ 5.desktop root:~> xchroot createstartup --desktop /dst/deb32/usr/share/xsessions/mate.desktop

xchroot and read only roots (aufs,unionfs)

xchroot is also handy if you wanna leave your target chroot environment untouched for any kind of reason. This may be a necessity if your chroot environment is located on a read only media like your cdrom drive. Simply use the --aufs/-a or --unionfs option and be sure that either aufs or unionfs is installed.

> xchroot --aufs /dst/debian

Readonly access is established like this: Changed files are copied to /tmp/xchroot/{aufs/unionfs}-$rootname-$$ where $$ is the pid of the invoker and $rootname the name of the directory you are chrooting-into. The mount point of the two combined directories (ro+rw) is /tmp/xchroot/mount-$rootname-$$.

It is a totally new feature of xchroot-2.3 that you can also save the temporary changes you have made to your chroot-environment into a squashfs-image. Squashfs images for unionfs and aufs will differ in the naming and storage of whiteout files. Whiteout files are hidden files that make a file of the ro-root appear deleted. xchroot will ask you for unsafed changes on exit; optionally you can specify the --save my-unionfs.squashfs --noask options to make that automatically and prevent any direct user interactions (keyboard usage). Use the --restore option on a saved image:

> xchroot --aufs --restore my-aufs.squashfs /dst/debian

When restoring elder changes an additional ro-branch mounted under /tmp/xchroot/squashfs-$rootname-$$ will be established. You may need to know about /tmp/xchroot whenever you issue a killall xchroot because then it will terminate immediately after listing the processes still running in the chroot-environment without performing the standard cleanup tasks. Do not kill these processes manually; use xchroot [--aufs/--unionfs [--restore xy]] cleanup $rootdir instead. It is recommended to specify the same options as before by only adding the keyword 'cleanup' before your root directory.

When using aufs you may want to mount /tmp or /tmp/xchroot to a tmpfs in ram especially when you are using a SSD or flashdisk because aufs needs some volatile files like the inode translation table. If you do not want to pack your changes into ram then you may want to use --unionopts xino=.. to relocate the inode translation table to a proper ramfs. Caution should be given with tmpfs. It makes the inode numbers wrap around if many files are created and deleted which can make aufs err. At the time of publishing xchroot it was not known if ramfs was affected by a similar problem.

> mount -t ramfs /dev/ram7 /tmp/xchroot
> mount -t tmpfs none /tmp (not so recommended)

If you wanna be absolutely sure not to confuse aufs you may also create an ext2 image in ram and mount it to /tmp/xchroot.

Note that some kind of partitions like ext4 partitions are not mountable if burnt to read only media because they seem only having been designed for rw-media always writing the last mount time. If you want to burn a root to blue ray in order to access it later on with xchroot use ext2 or JFS a fully fast and compatible filesystem also supported by OS/2 and eComstation

Making audio support work

For audio under Linux alsa is usually used for the hardware layer and pulseaudio as a software daemon. You may not hear any audio if the volume for the specified source is set to zero or if the wrong output target is selected for your application. Use alsamixer and pavucontrol to fix such issues. pavucontrol is for pulseaudio and additionally lets you select the audio sink for your application. If /run/user/1000/pulse has wrong permissions the volume utilities may not start (1000 is here the UID of the primary user). However this is fixed automatically by xchroot for the guest system.

However first of all make sure that your users are members of group audio. This is necessary to guarantee access to the devices and the hardware layer as done by Alsa. Pulseaudio normally runs on top of Alsa. See the section 'establishing users for a chroot environment' on how to change group membership and do not forget that effective group membership will not change unless you start a new session f.i. by invoking bash or xchroot. Check this with id -a.

Now the pulseaudio client starts the pulseaudio daemon for sound output on demand. It is started as user. Have a look at /dst/yourchroot/etc/pulse/client.conf for this purpose:

default-sink = alsa_output.pci-0000_04_07.0.analog-stereo ; also: $PULSE_SINK default-source = alsa_output.pci-0000_04_07.0.analog-stereo.monitor ; also: $PULSE_SOURCE ; default-server = /run/user/1000/pulse/native ; overrided by PULSE_SERVER envvar, may not be necessary or can even be harmful autospawn = yes extra-arguments = --log-target=syslog --realtime=true ; seems no more supported: --high-priorty=true

Important are the default-server and the autospawn lines. The stated default-server directory for users in /run/user/$UID is mounted automatically by xchroot unless --no-audio is given so that you will normally not even need autospawning inside the chroot, given that the users have the same id -u. The autospawn line is important to start the pulseaudio daemon when needed (either inside the root or outside your root if systemd did not do so). Make sure that it is not overrided by an /etc/pulse/client.conf.d/00-disable-autospawn.conf file and delete this file if necessary. The default-source and default-sink parameters can be used to override the default output sink and source for the pulseaudio applications you start. That can make sense as normally you will only use one output device and you do not want to set it with pavucontrol manually all the time. The extra-arguments line is here to add the --realtime=true and --high-priorty=true parameters which we have stated for better sound quality. However the right volume level is much more important to get a good sound quality. We have found that for our setting it was necessary to reduce the volume of the xine input stream at replay while the volume level at the output device did not cause quality issues. This is somewhat contraintuitive. However we suppose that there is a maximum volume which is cropped when being transgressed at the audio stream generation. You can see the extra-arguments parameters from before if you ps the pulseaudio daemon:

> ps axu | grep pulse elm 13436 2.2 0.3 723844 25712 ? S<sl 12:17 0:00 /usr/bin/pulseaudio --start --log-target=syslog --realtime=true --high-priority=true elm 13489 0.0 0.0 6156 828 pts/10 S+ 12:17 0:00 grep pulse

Now how to find out about the correct name of audio sink and source. At first you can query for them in the host system:

elm:~> /usr/bin/pactl info Failed to create secure directory (/run/user/1000/pulse): insufficient access rights #connection error: connection refused pa_context_new() failed: connection refused elm:~> sudo chown 1000 /run/user/1000/pulse elm:~> /usr/bin/pactl info Server String: /run/user/1000/pulse/native Library Protocol Version: 29 Server Protocol Version: 29 Is Local: yes Client Index: 34 Tile Size: 65472 User Name: elm Host Name: debian8 Server Name: pulseaudio Server Version: 5.0 Default Sample Specification: s16le 2ch 44100Hz Default Channel Map: front-left,front-right Default Sink: alsa_output.pci-0000_01_00.1.hdmi-stereo Default Source: alsa_output.pci-0000_01_00.1.hdmi-stereo.monitor Cookie: 4b9b:ab79

The problem with pactl and any other pusleaudio client from above can only arise in the host system as in the chroot xchroot will take care of the correct access privileges. Here you can see that the HDMI cable, i.e. the monitor cable for your display is used as default sound output which is from the graphics card. If you have another sound output, you would usually prefer this one as your monitor may either give no sound or sound output at a low quality. So how to find out about the correct audio sink and source names? Have a look at the following command:

elm:~> pactl list | grep alsa_output Name: alsa_output.pci-0000_01_00.1.hdmi-stereo Monitor Source: alsa_output.pci-0000_01_00.1.hdmi-stereo.monitor Name: alsa_output.pci-0000_04_07.0.analog-stereo Monitor Source: alsa_output.pci-0000_04_07.0.analog-stereo.monitor Name: alsa_output.pci-0000_01_00.1.hdmi-stereo.monitor Monitor of Sink: alsa_output.pci-0000_01_00.1.hdmi-stereo Name: alsa_output.pci-0000_04_07.0.analog-stereo.monitor Monitor of Sink: alsa_output.pci-0000_04_07.0.analog-stereo

audio support for additional users

You may want to run programs with different users in one session and still have audio support. Usually the pulseaudio daemon that shall be contacted is read from window properties of the root window; see xprop -root | grep PULSE. This will not work if you have programs of different users that run in one session with the same root window. You will normally need one pulseaudio daemon per user because of the access rights. Fortunately there is also an environment variable PULSE_SERVER that you can set to /run/user/$(id -u)/pulse/native. Though this path is a default, check if you need the environment variable.

It may be best to start /usr/bin/pulseaudio [--daemonize=no] as the desired user before invoking xchroot because /run/user/NNNN/pulse will be exported automatically to the chroot. Pulseaudio alone can´t establish audio access without Alsa so again make sure that the user at best inside and outside the chroot are members of group audio. If you want pulseaudio to be started inside the chroot check your configuration in /etc/pulse (last section) and enable autospawn twice. If it complains about module-console-kit disable it in /etc/pulse/ If the daemon does not start automatically see what error messages pulseaudio --start will give you.

get it! (downloads)

version 2.7.4 and before: Mageia 8 did not provide a valid xauth token and none was generated by xchroot, thus a manual xhost +SI:localuser:»targetusername« (or xhost +local for chrooting to any user) was required when changing the user.

xchroot v2.7.5 xauth mechanism rewritten: xauth token generation if none available due to xhost +SI:localuser:xx,
xchroot v2.7.4 bugfix: mntmp behaviour of v2.6, xchroot inst-root-sudo: effective against a regression in sudo, xchroot into minimal busybox, mounting resolv.conf (internet access), /boot/efi, initctl (systemctl suspend)
xchroot v2.7 whole desktop sessions with xchroot; dbus sessions; full changelog in head /bin/xchroot
xchroot v2.6 various bugfixes, xchroot escape, improved desktop file creation
xchroot v2.5.3 some important but yet not fully tested bugfixes towards v2.5
xchroot v2.5 mount-mirroring, cleanup: faster exit, message printing
xchroot v2.4.1 bugfix on unmounting, no spurious message on relative dir chroot, keep dir when already inside chroot
xchroot v2.4 + man page improved --quiet, added --genuine-retval, making use of chroot --userspec (changelog: see the first lines of the program)
xchroot v2.3.4 + man page improved --quiet, added --genuine-retval, making use of chroot --userspec (changelog: see the first lines of the program)
xchroot v2.3.3 + man page chroot: openroot between different users, security fix when users have same name but are different; cd into home directory; license update.
xchroot v2.3.2 + man page recom­mended security fixes; license update.
xchroot v2.3.1 + man page some minor bugfixes including XAUTHORITY handling for remote hosts; license allowing to distribute modified versions of xchroot
xchroot v2.3 renewed aufs & unionfs support; totally new features like --save & --restore
xchroot v2.25 several bugfixes towards v2.2; see changelog at beginning of file
xchroot v2.1 first comple­tely reworked edition; without aufs support
openroot v2.0 xchroot as it was called before
openroot v1.1 ancient xchroot (usage descouraged)
*** new *** covered by our gpg-signed software/SHA512SUMS.signed.
online changelog:
ViewRSS: xchroot
Elmar Stelln­berger


Since v2.3.4 xchroot is GPLv3. Please sign our Contributor License Agreement if you want to contribute code. Otherwise we can not assimilate and re-distribute your changes here at

Hint: Don`t forget to chmod +x xchroot; good place would be /usr/sbin and copy the man page renamed int xchroot.8.gz into /usr/share/doc/man/man8

rss-feed get informed about site updates via rss!  (right click: add with Akregator)


Britton Kerin wrote:

I love it, I hope you keep maintaining it, help propagate it into distros, etc.

I wanted to debug a weird assertion violation in inkscape that I suspect
is due to my weird random stack of gnome libs, I asked on garnome
list and even the garnome enthusiasts said to run in fear and just use
a chroot...

But of course chroot with X isn't totally automatic these days, until you
find openchroot! Thanks so much for this handy little script, it succeeded
where all the old broken advice on how to get X going in a chroot either
failed or wasn't what I wanted (I have no desire to restart X every time I
test of run an extra GDM or anything like that).

Very sweet.


Things that are new in version v2.4

general issues with audio support under Linux

At first you will of course need to make audio work for your host system. Here are some additional hints on this in addition to the hints from the last section. However the description here is completely independent from xchroot and can be used for any Linux system.

First of all note that viewing cotrols with pavucontrol and alsamixer may be insufficient. At me there was a hidden control for the SPDIF/IEC958 digital audio output:

> amixer controls numid=31,iface=MIXER,name='IEC958 Output Switch' … > amixer get 'IEC958 Output' Simple mixer control 'IEC958 Output',0 Capabilities: pswitch pswitch-joined Playback channels: Mono Mono: Playback [off] > amixer set 'IEC958 Output' unmute Simple mixer control 'IEC958 Output',0 Capabilities: pswitch pswitch-joined Playback channels: Mono Mono: Playback [on]

It may be handy to directly test and configure sound output at the alsa level. To do so set autospawn to no in /etc/pulse/client.conf and do a killall pulseaudio. Otherwise the alsa sources and sinks may be occupied and not free for use by aplay. Now you can test hardware devices like this: aplay -D hw:0,2 Track03.wav. But how to find out about the right output device? I knew from pavucontrol that IEC958 named my digital SPDIF output.

> cat /proc/asound/cards 0 [CMI8738 ]: CMI8738-MC6 - C-Media CMI8738 C-Media CMI8738 (model 55) at 0x3000, irq 21 2 [HDMI ]: HDA-Intel - HDA ATI HDMI HDA ATI HDMI at 0xfc220000 irq 35 > cat /proc/asound/devices 2: [ 0- 0]: digital audio playback 3: [ 0- 0]: digital audio capture 4: [ 0- 1]: digital audio playback 5: [ 0- 2]: digital audio playback 6: [ 0- 2]: digital audio capture 7: [ 0- 0]: raw midi 8: [ 0- 0]: hardware dependent 9: [ 0] : control 10: [ 2- 3]: digital audio playback 11: [ 2- 0]: hardware dependent 12: [ 2] : control 33: : timer > cat /proc/asound/card0/pcm2c/info card: 0 device: 2 subdevice: 0 stream: CAPTURE id: CMI8738-MC6 name: C-Media PCI IEC958 subname: subdevice #0 class: 0 subclass: 0 subdevices_count: 1 subdevices_avail: 1

Now not all output devices support all sampling rates. My Bose sound bar does f.i. work well at 48kHz or 96kHz but not at 192kHz. You may define rate settings in a file often called /etc/asound.conf. However at me I had to create such a file /usr/share/alsa/alsa.conf.d. ~/.asoundrc should also do it. There you can define aliases used with aplay -D instead of hw0,1.

pcm.raw3 { type hw card 0 device 2 }

Test with aplay whether the target is avaiable and the config file has been parsed correctly. Here is a way to define a default sampling rate for such a device:

pcm_slave.slout3 { pcm "hw:0,2" rate 96000 } pcm.out3 { type rate slave slout3 }

If you do not have a .wav file handy for testing, speaker-test is what you want: speaker-test -c2 --device out3 [--rate 48000]. The tool is said to also initialize some parameters so playback may work better/ start to work after an invocation.

Finally make sure whether your sound card requires some additional firmware support. For Debian the usually proprietary firmware does not get installed automatically. However it can be downloaded from Then you can query for sound support by the Linux kernel via ls /sys/class/sound/. In our case we have two sound cards card0 and card2. The kernel driver for a sound card can be obtained like this:

> cat /sys/class/sound/card0/device/uevent DRIVER=snd_ens1371 PCI_CLASS=40100 PCI_ID=1274:1371 PCI_SUBSYS_ID=1274:1371 PCI_SLOT_NAME=0000:04:07.0 MODALIAS=pci:v00001274d00001371sv00001274sd00001371bc04sc01i00 > lspci | grep 04:07.0 04:07.0 Multimedia audio controller: Ensoniq ES1371 / Creative Labs CT2518 [AudioPCI-97] (rev 08) > modinfo snd_ens1371 filename: /lib/modules/4.19.67-rt24/kernel/sound/pci/snd-ens1371.ko description: Ensoniq/Creative AudioPCI ES1371+ license: GPL author: Jaroslav Kysela , Thomas Sailer alias: pci:v00001102d00008938sv*sd*bc*sc*i* alias: pci:v00001274d00005880sv*sd*bc*sc*i* alias: pci:v00001274d00001371sv*sd*bc*sc*i* depends: snd-pcm,snd,snd-rawmidi,gameport,snd-ac97-codec retpoline: Y intree: Y name: snd_ens1371 vermagic: 4.19.67-rt24 SMP preempt mod_unload modversions parm: index:Index value for Ensoniq AudioPCI soundcard. (array of int) parm: id:ID string for Ensoniq AudioPCI soundcard. (array of charp) parm: enable:Enable Ensoniq AudioPCI soundcard. (array of bool) parm: joystick_port:Joystick port address. (array of int) parm: spdif:S/PDIF output (-1 = none, 0 = auto, 1 = force). (array of int) parm: lineio:Line In to Rear Out (0 = auto, 1 = force). (array of int)

The actual model parameters can be queried via /sys/class/sound/card2/device/driver/module/parameters/ and stated at modprobe time. Before you can actually re-insert a kernel module you may need to remove it with rmmod -f. Query with lsmod | grep name whether it is loaded. Set boot time module parameters in /etc/modprobe.d/:

> cat /etc/modprobe.d/modesetting.conf options cirrus modeset=1 options mgag200 modeset=1

The lines from above show module parameters for some graphics cards. Similarely to audio graphics cards may require the right firmware to be installed.