openroot is now called xchroot:

xchroot

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


This page can be viewed online at www.elstel.org/xchroot

Introduction

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 should always be possible. 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) is in place that is able to controlle your X server and adherent programs like DBUS; be it a 'secured' chroot environment or not. That can be as simple as pasting text into a root console and letting it disappear by appropriate escape sequences fractions of milliseconds thereafter!

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 checkroot 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 on by default now for reasons of security in distributions like openSUSE. In this case you would have to replicate the socket file /tmp/.X11-unix/X0 to /dst/debian/tmp/.X11-unix/X0 which can be done by a proper socat rather than a pure symbolic link. 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. 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

Replicating the appropriate socket and setting $DISPLAY to the socket/display number is not the only thing you will have to do. X servers use to use an additional authentication mechanism based on cookies. The cookies are transmitted unencrypted to the X server so that they can be eavesdropped by anyone listening on 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. 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.

Furthermore as already discuessed programs like grub or gparted 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.

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/openroot is already running a normal chroot should also suffice as long as you terminate the openroot/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 it to chroot as user. The --user option and sudo will serve this purpose. 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 or via /etc/sudoers:

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. ('ALL' is just your host name in case that the /etc/sudoers is distributed to many hosts but should not allow 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 in sudoers.

Now we do also want to pass user parameters to xchroot. Unfortunately we can not put these parameters in front of our root /dst/* (which stands for 'distribution') because otherwise we could also wildcard our root 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 option after a '--' at the end right after your root and program specification. 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. Note that the --user option can not be used as tail option because that would compromize our security needs.

Rather complicated?
Yes it is. This is why we have invented a macro called openroot in order to xchroots more easily as user (Well we could also have called the user macro xchroot but that might have been subject to further confusion.). Get it installed into your .bashrc which executes automatically on any bash login:

elm:~> xchroot bashrclines openroot() { sudo /usr/sbin/xchroot -u $(whoami) "$@" --env XCHROOT_MYROOT="$XCHROOT_MYROOT" --env XAUTHORITY="$XAUTHORITY" --env DISPLAY="$DISPLAY"; } elm:~> xchroot bashrclines >>~/.bashrc elm:~> source ~/.bashrc

Now just have a little time to disfruit our new macro:

elm:~> openroot /dst/debchroot elm:~> openroot -t /dst/debchroot -- --aufs

xchroot and users: the easy way

xchroot has a user wrapper called openroot: It can invoke xchroot via sudo as user.

Now before we can use openroot we need to execute some administration commands as root to set up proper access rights for users.

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

Now let us have a look at the preceding commands. 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 an openroot upon /dst/debchroot and only upon this directory. Finally we list all sudoer entries: addsudoers adds four sudoer entries for every access record: Allowing to invoke openroot with and without tail opts ([-]t) and finally allowing to issue cleanups for whenever you have invoked openroot 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:~> openroot /dst/debchroot/ elm:~> openroot -t /dst/debchroot/ -- --aufs

The first one does not need any option, 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 --. Now to make this work you need to add the openroot macro to your ~/.bashrc first:

elm:~> xchroot bashrclines >>~/.bashrc elm:~> source ~/.bashrc

The first line installs the openroot macro in your basrc (do a grep openroot ~/.bashrc to see whether it is already installed), the second line fetches the changes of your bashrc for the current session.

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:~> openroot /dst/debchroot/
xchroot - visit us on www.elstel.org/xchroot
----------------------------------------------------------- chroot /dst/debchroot /tmp/xchroot/startup-15842 Debian GNU/Linux 7 \n \l debchroot_elm:~> goldendict & ...

establishing users for a chroot environment

Now it may be the case that you have already set up openroot correctly for users but that your target chroot environment does not have the same users from which you want to issue an openroot. Simply do the following for the user elm:

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 Stellnberger:/home/elm:/bin/bash root:~> grep 100 /etc/group users:x:100: root:~> grep 100 /dst/debchroot/etc/group users:x:100:

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

root:~> usermod --groups video,vboxusers elm root:~> grep elm /etc/group video:x:33:gdm,elm vboxusers:x:477:elm

Xorg/X11 access as root

Now it may be the case that you have Xorg access by issuing an openroot 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/openroot but which may be very useful in the context of openroot. 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
by Elm.Stb.(c); usable under S-FSL v1.3.6 under http://www.elstel.org/license.

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

xchroot and changeable media

xchroot does also mount changeable media under /media into your chroot environment. While this has proven to be practical in many situations you have to take special care when removing your changeable media during an xchroot session. Make sure that all mount points are unmounted i.e. /media/xx, /chroot/media/xxx etc.. You can check for all removable media mounts by issuing sth. like mount | grep sd[^ab] given that you have two non-removable disks called sda and sdb. Note that /media-mounting is currently only done on startup.

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 /var/xchroot/suse11.2 http://debian.uni-klu.ac.at/debian

In Suse use zypper with the --root option to add repositories and install software:

> mkdir /var/xchroot/suse11.2 > mount /dev/sr0 /media/dvd > zypper --root /xchroot/suse11.2 ar /media/dvd/ dvd Repository 'dvd' wird hinzugefügt [fertig] Repository 'dvd' erfolgreich hinzugefügt Aktiviert: Ja Autoaktualisierung: Nein URI: dir:///media/dvd > zypper --root /xchroot/suse11.2 lr # | Alias | Name | Aktiviert | Aktualisieren --+-------+------+-----------+-------------- 1 | dvd | dvd | Ja | Nein > zypper --root /xchroot/suse11.2 in rpm zypper xterm

get it!

Download:
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 recommended 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 completely reworked edition; without aufs support
openroot v2.0 xchroot as it was called before
openroot v1.1 ancient xchroot (usage descouraged)
*** new *** download as package for your distribution.

Author:
Elmar Stellnberger estellnb@elstel.org
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






licensing

From xchroot-2.3 on xchroot has been furnished with a new oss-compliant license that allows packaging and contribution in any free Linux distro. Those who have already downloaded xchroot with the more restricted ancient license may still continue to use these elder versions under the old license.

Comments

Britten 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.

Britton