Chroot: Difference between revisions

From Alpine Linux
(Some cleanup)
m (The directions on the page seem to work...)
 
(24 intermediate revisions by 6 users not shown)
Line 1: Line 1:
{{Draft}}
"Changing root" or "chrooting" is a method for zooming in on part of your filesystem, so that, for example, {{Path|/path}} will refer to what was formerly accessible at {{Path|/mnt/path}}. The "root" in the expression "chroot" refers to the root filesystem {{Path|/}}, not to the root user. (Though typically you will need root user privileges in order to chroot.)
"Changing root" or "chrooting" is a method for zooming in on part of your filesystem, so that, for example, {{Path|/path}} will refer to what was formerly accessible at {{Path|/mnt/path}}. The "root" in the expression "chroot" refers to the root filesystem {{Path|/}}, not to the root user. (Though typically you will need root user privileges in order to chroot.)


A common reason for chrooting is to perform maintenance on existing systems where booting and/or logging in no longer works. One has to boot the hardware somehow, such as with an Installation or Rescue CD or USB; then one mounts the broken system and chroots into it and performs the repairs. Common examples are:
A common reason for chrooting is to perform maintenance on existing systems where booting and/or logging in no longer works. One has to boot the hardware somehow, such as with an Installation or Rescue CD or USB; then one mounts the broken system and chroots into it and performs the repairs. Common examples are:


* reinstalling the bootloader
* reinstalling the [[Bootloaders|bootloader]]
* rebuilding the initramfs image
* rebuilding the initramfs image
* upgrading or downgrading packages
* upgrading or downgrading packages
Line 17: Line 15:
* Open file descriptors (for files, pipelines and network connections) can be "carried into" the chroot by running programs, making it unnecessary for those programs' working files to be visible inside the chroot directory. This can help separate privileges or design sandboxes. Note that chroot is not a secure way to contain a hostile process with root privileges. See Wikipedia's [https://en.wikipedia.org/wiki/Chroot#Limitations discussion of some of chroot's limits].
* Open file descriptors (for files, pipelines and network connections) can be "carried into" the chroot by running programs, making it unnecessary for those programs' working files to be visible inside the chroot directory. This can help separate privileges or design sandboxes. Note that chroot is not a secure way to contain a hostile process with root privileges. See Wikipedia's [https://en.wikipedia.org/wiki/Chroot#Limitations discussion of some of chroot's limits].


Here are some other resources:
Scripts for installing Alpine Linux that use chroot:
* [https://github.com/alpinelinux/alpine-chroot-install alpine-chroot-install]
* [https://github.com/alpinelinux/alpine-make-vm-image alpine-make-vm-image]
* [https://github.com/jirutka/alpine-make-rootfs alpine-make-rootfs]


* [http://superuser.com/questions/111152 What's the proper way to prepare chroot to recover a broken Linux installation?]
* [http://wiki.archlinux.org/index.php/Change_Root ArchLinux wiki on "Change Root"]
* [http://wiki.archlinux.org/index.php/Reinstalling_GRUB ArchLinux Wiki on "Reinstalling GRUB"]
* [http://en.gentoo-wiki.com/wiki/Chroot_from_a_livecd Gentoo Wiki on "Chroot from a livecd"]
* [https://help.ubuntu.com/community/BasicChroot Ubuntu wiki on "Basic chroot"]


== Preparation ==
== Preparation ==
Line 52: Line 48:
<li>Set up your network if you'll need it inside the chroot, e.g., to install updated packages. The script presented below will copy the {{Path|/etc/resolv.conf}} from the host system, but will prompt before overwriting an existing {{Path|etc/resolv.conf}} inside the chroot. If you like, you can generate one from scratch by doing:
<li>Set up your network if you'll need it inside the chroot, e.g., to install updated packages. The script presented below will copy the {{Path|/etc/resolv.conf}} from the host system, but will prompt before overwriting an existing {{Path|etc/resolv.conf}} inside the chroot. If you like, you can generate one from scratch by doing:
{{Cmd|echo 'nameserver 8.8.8.8' > $CHROOT/etc/resolv.conf}}
{{Cmd|echo 'nameserver 8.8.8.8' > $CHROOT/etc/resolv.conf}}
<li>If your host system is Alpine or another distribution (like Hardened Gentoo) that uses the grsecurity kernel patches, for some maintenance tasks you'll want to make sure some of the grescurity prohibitions are disabled. For example:
{{Cmd|sysctl -w kernel.grsecurity.chroot_deny_chmod{{=}}0 # enable suid/sgid<br>sysctl -w kernel.grsecurity.chroot_deny_mknod{{=}}0<br>sysctl -w kernel.grsecurity.chroot_deny_mount{{=}}0<br>sysctl -p}}
For more info, see:
* http://en.wikibooks.org/wiki/Grsecurity
* http://www.gentoo.org/proj/en/hardened/grsecurity.xml


</ul>
</ul>
Line 66: Line 55:
The most reliable way to chroot is to use the following script:
The most reliable way to chroot is to use the following script:


{{Cat|/root/start-chroot|<nowiki>
{{Cat|/root/start-chroot|{{:Chroot/start-chroot}}}}
#!/bin/sh -e
user=`whoami`
if [ "$user" != "root" ]; then
  echo "This script needs root access" >&2
  exit 1
fi
if ! [ -d "$1" ]; then
  echo "Usage: $0 <chroot directory>" >&2
  exit 1
fi
if [ x1 = x`sysctl -ne kernel.grsecurity.chroot_deny_chmod` ]; then
  echo "Warning: can't suid/sgid inside chroot" >&2
fi
if [ x1 = x`sysctl -ne kernel.grsecurity.chroot_deny_chroot` ]; then
  echo "Warning: can't chroot inside chroot" >&2
fi
if [ x1 = x`sysctl -ne kernel.grsecurity.chroot_deny_mknod` ]; then
  echo "Warning: can't mknod inside chroot" >&2
fi
if [ x1 = x`sysctl -ne kernel.grsecurity.chroot_deny_mount` ]; then
  echo "Warning: can't mount inside chroot" >&2
fi
cd "$1"
shift
cp -L /etc/resolv.conf ./etc/ || true
mount -t proc proc ./proc
mount -t sysfs sys ./sys
mount -o bind /dev ./dev
# next line is said to be important for pacman's signature check
mount -o bind /dev/pts ./dev/pts
case $1 in
  -l) shift;;
  -l*) one=${1#-l}; shift; set -- -$one "$@";;
esac
chroot . /bin/sh -l "$@"
umount ./dev/pts
umount ./dev ./sys ./proc
</nowiki>}}


Copy that script to some location on your system, such as {{Path|/root/start-chroot}}, run <code>chmod +x</code> on it, and then invoke it as: {{Cmd|/root/start-chroot $CHROOT}}, where <code>$CHROOT</code> evaluates to the path you want to chroot into (for example, {{Path|/mnt}}).


'''Comment on Environment variables, extra arguments to start-chroot.'''
Copy that script to some location on your system, such as {{Path|/root/start-chroot}}, run <code>chmod +x</code> on it, and then invoke it as:
{{Cmd|/root/start-chroot $CHROOT}}
 
{{Todo|Comment on Environment variables, extra arguments to start-chroot}}


It is certainly possible to perform a chroot by hand, without using this script. For some purposes, you can get away with a simpler procedure than the script follows. But it's hard to catalogue in advance when taking shortcuts will get you in trouble, so it's best to just get in the habit of using this script (or doing the same things it does). As you read around in various wikis (perhaps including this one), you will encounter a variety of instructions for how to chroot by hand. These instructions often differ in small details from each other and are usually not as thorough as the above script.
It is certainly possible to perform a chroot by hand, without using this script. For some purposes, you can get away with a simpler procedure than the script follows. But it's hard to catalogue in advance when taking shortcuts will get you in trouble, so it's best to just get in the habit of using this script (or doing the same things it does). As you read around in various wikis (perhaps including this one), you will encounter a variety of instructions for how to chroot by hand. These instructions often differ in small details from each other and are usually not as thorough as the above script.




=== Troubleshooting ===


<!--
If you see the error:


Performing the chroot
* <code>chroot: cannot run command '/bin/sh': Exec format error</code>, it is likely that the architectures of the host environment and the chroot environment do not match. For example, you booted with a 32bit Live CD and are trying to chroot into an x86_64 system.
---------------------
* <code>chroot: '/bin/sh': Permission denied</code>, try remounting the system with exec permissions: <code>mount -o remount,exec $CHROOT</code>


    cd /
== Inside the chroot ==
    mount -t ext3 /dev/sda1 /mnt
    mount -t proc proc /mnt/proc
    mount -t sysfs sys /mnt/sys
    mount -o bind /dev /mnt/dev


If your `/boot` directory is on a different partition from your `/`, and you want to manipulate files on it (e.g., if you'll be working with GRUB, performing a kernel upgrade, etc.), you'll also need to mount that partition. If it's at /dev/sda2 and its filetype is ext2, then do:
At this point, you're still running the kernel you booted with, but all paths {{Path|/path}} will refer to what used to be {{Path|$CHROOT/path}}.


    mount -t ext2 /dev/sda2 /mnt/boot
If you have multiple terminals open on or connected to the running system, the chroot will only be effective in the terminal that you performed it in.


Similarly for any other parts of your filesystem (`/var`, `/usr`) that reside on separate partitions but which you need access to. Generally when you're chrooting to fix something you won't need access to /home, so you don't need to bother with it.
Now you can perform whatever troubleshooting (or do whatever development work) you need to do:


(It's also possible to mount filesystems after you've chrooted, but it's smarter to do so beforehand. The reason is that when you do it after, the outside/kernel environment won't know about the mounted filesystems, so if you forget to umount them before exiting the chroot, the system won't know to umount them when it shuts down, either. This could damage those filesystems.)
* resintall GRUB to your disk's MBR
 
* rebuild your initramfs image
If you've setup your network and want to use it in the chrooted system, copy over `/etc/resolv.conf` so that you'll be able to resolve domain names:
* fix your {{Path|/etc/fstab}}
 
* perform a kernel upgrade (or downgrade)
    cp -L /etc/resolv.conf /mnt/etc/resolv.conf
* (re)install other packages using your package manager
 
* reset a forgotten password
Now you're ready to move into the mounted filesystem:
 
    chroot /mnt /bin/bash
 
(If this returns an error `chroot: cannot run command '/bin/bash': Exec format error`, this usually indicates that you booted with one architecture (e.g. x86_32) and are trying to chroot into another (e.g. x86_64). The solution is to use a LiveCD which has the same architecture as the system you want to chroot into.)
 
At this point, you're still running the kernel you booted with, but all paths `/path` will refer to what used to be `/mnt/path`.


If you'll be doing anything with GRUB, you'll need to be sure your `/etc/mtab` file is up-to-date:
or whatever.


    grep -v rootfs /proc/mounts > /etc/mtab
If you'll be doing anything with GRUB, you should first make sure that sure your {{Path|/etc/mtab}} file is up-to-date:
{{Cmd|grep -v rootfs /proc/mounts > /etc/mtab}}




It might also be helpful at this point to do:


    source /etc/profile
=== Run graphical applications from the chroot ===
    export PS1="(chroot) $PS1"  # add a reminder to your prompt


-->
If you have an X server running on your outside/host system, you can start graphical applications from inside the chroot. To allow the chroot environment to connect to the X server, you have to do this in the host system (either before chrooting, or in a terminal other than the one you performed the chroot in):
 
{{Cmd|xhost +local:}}
 
 
== Inside the chroot ==
 
Now that you're inside the chroot, you can perform whatever troubleshooting you need to do:
 
* resintall GRUB to your disk's MBR
* reset a forgotten password
* perform a kernel upgrade (or downgrade)
* rebuild your initramdisk
* fix your /etc/fstab
* reinstall packages using your package manager
* whatever
 
If you have multiple terminals open on or connected to the running system, the chroot will only be effective in the terminal that you performed it in.


Then, to direct applications from the chroot to the X server, set the <code>DISPLAY</code> environment variable inside the chroot to match its value in the host environment (for the user who owns the X server). So for example, inside the chroot you might say:
{{Cmd|export DISPLAY{{=}}:0}}


== Cleaning up ==
== Cleaning up ==
<!--


When you're finished, ensure that all running programs have stopped. Then exit the chroot:
When you're finished, ensure that all running programs have stopped. Then exit the chroot:
{{Cmd|exit}}


    exit
If you started the chroot using the {{Path|start-chroot}} script, it will take care of umounting {{Path|/dev}}, {{Path|/proc}}, {{Path|/sys}}, {{Path|/tmp}}, and so on. Else you should do this by hand. In any case, you should umount any partitions like {{Path|/boot}} that you mounted yourself, and then umount the system partition at <code>$CHROOT</code> if appropriate.


Now unmount all the partitions you mounted:
If you get an error saying that <code>$CHROOT</code> (or any partition inside it) is busy, this can mean one of two things:


    umount /mnt/boot # if you mounted this or any other separate partitions
* A program was left running inside of the chroot.
    umount /mnt/{proc,sys,dev}
* Or more frequently, a mountpoint still exists on this mount. For example, {{Path|$CHROOT/usr}} is still mounted when trying to umount {{Path|$CHROOT}}.


Finally attempt to unmount your hard drive:
In the latter case, simply unmount the offending mountpoint first. To get a reminder of all the current mountpoints, run <code>mount</code> with no parameters.


    umount /mnt


If you get an error saying that /mnt (or any other partition) is busy, this can mean one of two things:
== Other Resources ==


  - A program was left running inside of the chroot.
* [https://superuser.com/questions/111152 What's the proper way to prepare chroot to recover a broken Linux installation?]
 
* [https://wiki.archlinux.org/title/Chroot ArchLinux wiki on "Change Root"]
  - Or more frequently: a mount point still exists on this mount. For example, /mnt/usr is still mounted when trying to unmount /mnt.
* [https://web.archive.org/web/20130412163442/http://en.gentoo-wiki.com/wiki/Chroot_from_a_livecd Gentoo Linux Wiki: Chroot from a livecd (via archive.org)]
 
* [https://help.ubuntu.com/community/BasicChroot Ubuntu wiki on "Basic chroot"]
In the latter case, simply unmount the offending mount point first. To get a reminder of all the current mount points, run `mount` with no parameters.
 
Finally:
 
    reboot


-->
[[Category:System Administration]]

Latest revision as of 18:09, 13 January 2024

"Changing root" or "chrooting" is a method for zooming in on part of your filesystem, so that, for example, /path will refer to what was formerly accessible at /mnt/path. The "root" in the expression "chroot" refers to the root filesystem /, not to the root user. (Though typically you will need root user privileges in order to chroot.)

A common reason for chrooting is to perform maintenance on existing systems where booting and/or logging in no longer works. One has to boot the hardware somehow, such as with an Installation or Rescue CD or USB; then one mounts the broken system and chroots into it and performs the repairs. Common examples are:

  • reinstalling the bootloader
  • rebuilding the initramfs image
  • upgrading or downgrading packages
  • resetting a forgotten password

Chrooting can also be used to create and host a separate virtualized installation of a system. This can be useful for:

  • Testing and development, with software that's too risky to deploy on a production system.
  • Software can be developed, built and tested in a chroot populated only with its expected dependencies.
  • Can run legacy software or other software whose supporting libraries or data files can't be installed in the host system.
  • Open file descriptors (for files, pipelines and network connections) can be "carried into" the chroot by running programs, making it unnecessary for those programs' working files to be visible inside the chroot directory. This can help separate privileges or design sandboxes. Note that chroot is not a secure way to contain a hostile process with root privileges. See Wikipedia's discussion of some of chroot's limits.

Scripts for installing Alpine Linux that use chroot:


Preparation

  • All the steps in this guide will have to be performed as root user.
  • If you are using chroot to repair an existing Linux system, it will need to be mounted first. If you don't know the location and/or filetype of the disk(s) where it resides, read the output of fdisk -l or lsblk. We will suppose the broken system is at /dev/sdx1 and its filetype is ext3. Create a directory for mounting this disk, and mount it:

    mkdir -p $CHROOT
    mount -t ext3 /dev/sdx1 $CHROOT

    where $CHROOT evaluates to the path you want to chroot into (for example, /mnt).

    If the system directory is encrypted or in a LVM group or anything like that, we'll leave it to you to figure out what steps to take to prepare it and mount it.

  • If there are separate filesystems for other directories (such as /boot, /var, /usr, /home), mount them too:

    mount /dev/sdx2 $CHROOT/boot
    mount /dev/sdx3 $CHROOT/var
    mount /dev/sdx4 $CHROOT/usr

    For many repair tasks, you may not need to mount the broken system's /home directory.

    If you do have /boot on a separate partition, it's essential to have it mounted before working with GRUB, performing a kernel upgrade, or anything of that sort. It's also possible to mount some of these filesystems after you've chrooted, and in some cases mounting /boot in particular after chrooting has worked better with GRUB. If you can, though, it's smarter to mount these beforehand. The reason is that if you do it from inside the chroot, the outside/host environment won't know about the mounted filesystems, so if you forget to umount them before exiting the chroot, the system won't know to umount them when it shuts down, either. That could damage those filesystems.

  • The script presented below will take care of generating or remounting other system directories like /dev, /proc, /sys, /tmp and so on.
  • The architecture of the host system you're booted into (e.g., if it's a 32bit LiveCD, that's x86) and the system you want to chroot into must match. You can determine what architecture you're booted into using uname -m.
  • Before chrooting, be sure any kernel modules you'll need when working inside the chroot have been loaded. For example:

    modprobe dm-mod
    modprobe dm-crypt

  • Set up your network if you'll need it inside the chroot, e.g., to install updated packages. The script presented below will copy the /etc/resolv.conf from the host system, but will prompt before overwriting an existing etc/resolv.conf inside the chroot. If you like, you can generate one from scratch by doing:

    echo 'nameserver 8.8.8.8' > $CHROOT/etc/resolv.conf

Performing the chroot

The most reliable way to chroot is to use the following script:

Contents of /root/start-chroot

#!/bin/sh -e if [ 0 -ne `id -u` ]; then echo "This script needs root access" >&2 exit 1 fi if ! [ -d "$1" ] || [ x-h = x"$*" ] || [ x--help = x"$*" ]; then echo "Usage: ${0##*/} <chroot_directory>" >&2 exit 1 fi cd "$1" if ! [ -d ./etc ]; then echo "No etc directory inside $1" >&2 exit 1 fi shift MOUNTED= umount_all() { case $MOUNTED in shm\ *) if [ -L ./dev/shm ]; then umount ./`readlink ./dev/shm` else umount ./dev/shm fi MOUNTED=${MOUNTED#shm };; esac case $MOUNTED in run\ *) umount ./run MOUNTED=${MOUNTED#run };; esac case $MOUNTED in tmp\ *) umount ./tmp MOUNTED=${MOUNTED#tmp };; esac case $MOUNTED in proc\ *) umount ./proc MOUNTED=${MOUNTED#proc };; esac case $MOUNTED in sys\ *) umount ./sys MOUNTED=${MOUNTED#sys };; esac case $MOUNTED in pts\ *) umount ./dev/pts MOUNTED=${MOUNTED#pts };; esac case $MOUNTED in dev\ *) umount ./dev MOUNTED=${MOUNTED#dev };; esac } trap 'umount_all' EXIT #mkdir -p ./etc ./dev/pts ./sys ./proc ./tmp ./run ./boot ./root cp -iL /etc/resolv.conf ./etc/ || true # if ^C, will cancel script mount --bind /dev ./dev MOUNTED="dev $MOUNTED" mount -t devpts devpts ./dev/pts -o nosuid,noexec MOUNTED="pts $MOUNTED" mount -t sysfs sys ./sys -o nosuid,nodev,noexec,ro MOUNTED="sys $MOUNTED" mount -t proc proc ./proc -o nosuid,nodev,noexec MOUNTED="proc $MOUNTED" mount -t tmpfs tmp ./tmp -o mode=1777,nosuid,nodev,strictatime MOUNTED="tmp $MOUNTED" mount -t tmpfs run ./run -o mode=0755,nosuid,nodev MOUNTED="run $MOUNTED" if [ -L ./dev/shm ]; then mkdir -p ./`readlink ./dev/shm` mount -t tmpfs shm ./`readlink ./dev/shm` -o mode=1777,nosuid,nodev else #mkdir -p ./dev/shm mount -t tmpfs shm ./dev/shm -o mode=1777,nosuid,nodev fi MOUNTED="shm $MOUNTED" case $1 in -l) shift;; -l*) one=${1#-l}; shift; set -- -"$one" "$@";; esac chroot . /usr/bin/env -i SHELL=/bin/sh HOME=/root TERM="$TERM" \ PATH=/usr/sbin:/usr/bin:/sbin:/bin PS1='chroot # ' /bin/sh -l "$@" # FIXME # are USER and LOGNAME set automatically? # perhaps: source /etc/profile && export PS1="chroot $PS1"


Copy that script to some location on your system, such as /root/start-chroot, run chmod +x on it, and then invoke it as:

/root/start-chroot $CHROOT

Todo: Comment on Environment variables, extra arguments to start-chroot


It is certainly possible to perform a chroot by hand, without using this script. For some purposes, you can get away with a simpler procedure than the script follows. But it's hard to catalogue in advance when taking shortcuts will get you in trouble, so it's best to just get in the habit of using this script (or doing the same things it does). As you read around in various wikis (perhaps including this one), you will encounter a variety of instructions for how to chroot by hand. These instructions often differ in small details from each other and are usually not as thorough as the above script.


Troubleshooting

If you see the error:

  • chroot: cannot run command '/bin/sh': Exec format error, it is likely that the architectures of the host environment and the chroot environment do not match. For example, you booted with a 32bit Live CD and are trying to chroot into an x86_64 system.
  • chroot: '/bin/sh': Permission denied, try remounting the system with exec permissions: mount -o remount,exec $CHROOT

Inside the chroot

At this point, you're still running the kernel you booted with, but all paths /path will refer to what used to be $CHROOT/path.

If you have multiple terminals open on or connected to the running system, the chroot will only be effective in the terminal that you performed it in.

Now you can perform whatever troubleshooting (or do whatever development work) you need to do:

  • resintall GRUB to your disk's MBR
  • rebuild your initramfs image
  • fix your /etc/fstab
  • perform a kernel upgrade (or downgrade)
  • (re)install other packages using your package manager
  • reset a forgotten password

or whatever.

If you'll be doing anything with GRUB, you should first make sure that sure your /etc/mtab file is up-to-date:

grep -v rootfs /proc/mounts > /etc/mtab


Run graphical applications from the chroot

If you have an X server running on your outside/host system, you can start graphical applications from inside the chroot. To allow the chroot environment to connect to the X server, you have to do this in the host system (either before chrooting, or in a terminal other than the one you performed the chroot in):

xhost +local:

Then, to direct applications from the chroot to the X server, set the DISPLAY environment variable inside the chroot to match its value in the host environment (for the user who owns the X server). So for example, inside the chroot you might say:

export DISPLAY=:0

Cleaning up

When you're finished, ensure that all running programs have stopped. Then exit the chroot:

exit

If you started the chroot using the start-chroot script, it will take care of umounting /dev, /proc, /sys, /tmp, and so on. Else you should do this by hand. In any case, you should umount any partitions like /boot that you mounted yourself, and then umount the system partition at $CHROOT if appropriate.

If you get an error saying that $CHROOT (or any partition inside it) is busy, this can mean one of two things:

  • A program was left running inside of the chroot.
  • Or more frequently, a mountpoint still exists on this mount. For example, $CHROOT/usr is still mounted when trying to umount $CHROOT.

In the latter case, simply unmount the offending mountpoint first. To get a reminder of all the current mountpoints, run mount with no parameters.


Other Resources