Changement de racine - chroot

Mise à jour : Debian 10.8 / Buster

Le changement de racine a pour objectif d'ouvrir et exploiter un shell sur un système de fichier dont la racine est différente de celle utilisée pour démarrer. Cette technique permet par exemple de prendre la main sur un système qui ne démarre plus (problème de boot) et de tenter de le réparer.

Le principe consiste, après avoir démarré sur un premier système (distribution installée ou distribution live), à monter la racine du système "à dépanner" sur ce premier système. Le changement de racine permet alors d'intervenir, depuis la console du premier système, sur le second système.

Pour fonctionner les deux systèmes doivent être "proches" et fonctionner sous la même architecture : par exemple, deux debians 32 bits ou 64 bits.

1 - Préalable

Dans ce qui suit, le premier système démarré est situé sur le disque /dev/sda, le système sur lequel on veut intervenir par un changement de racine est situé sur un disque externe /dev/sdb.

Démarrer le premier système et vérifier les partitions et leurs points de montage.

$ lsblk -f
NAME FSTYPE LABEL UUID MOUNTPOINT
sda
├─sda1 ext4 debian8 a42b8919-e6a8-49e0-845e-6feb76b02297 /
├─sda2 swap swap e08131c8-298b-4368-81e4-502c3b83bef5 [SWAP]
└─sda3 ext4 home 78f7dc86-7d34-45aa-80c0-99538d77a3f7 /home
sdb
├─sdb1 ext4 debian8usb cf5a0c1d-9a16-4010-bb2a-29da4c8e23e6
├─sdb2 swap swapusb 332cd5f3-6008-4645-8668-5675a2b93497
└─sdb3 ext4 homeusb 1b6b8ae2-3f7e-4e2e-ad2d-09093726fc95

2 - Montage du système de fichier

$ sudo mount /dev/sdb1 /mnt
$ sudo mount /dev/sdb3 /mnt/home
$ sudo mount --bind /proc     /mnt/proc
$ sudo mount --bind /sys /mnt/sys
$ sudo mount --bind /sys/firmware/efi/efivars # Pour pouvoir utiliser efibootmgr
$ sudo mount --bind /dev /mnt/dev # Pour l'accès aux partitions externes, par exemple, pour la mise en place de grub sur la MBR
$ sudo mount --bind /dev/pts /mnt/dev/pts # Évite le message : E: Impossible d'écrire le journal (Est-ce que /dev/pts est monté ?) - posix_openpt (2: Aucun fichier ou dossier de ce type)
$ sudo mount --bind /run /mnt/run # Évite le message sudo: unable to resolve host xxxxxxx : Name or service not known

La commande peut être résumée en :

$ sudo -- bash -c 'for i in {proc,sys,sys/firmware/efi/efivars,dev,dev/pts,run};do mount --bind /$i /mnt/$i;done'

3 - Changement de racine

3.1 - Ouverture du shell

3.1.1 Ouverture d'un shell super-utilisateur

$ sudo chroot /mnt

Désormais le shell est ouvert, en tant que super-utilisateur, à la racine du système chrooté /.

3.1.2 Ouverture d'un shell utilisateur non privilégié

$ sudo -- bash -c 'chroot --userspec nom_utilisateur:nom_utilisateur /mnt'

Les identifiants utilisateur (par exemple 1000:1000) peuvent également être utilisés.

bash: /root/.bashrc: Permission non accordée

Se déplacer dans un répertoire utilisateur, par exemple, en l'indiquant par son chemin complet (ne pas utiliser ~ qui désigne alors le home du super-utilisateur) :

$ cd /home/nom_utilisateur

3.2 - Vérification du chroot

# [[ "$(stat -c %d:%i /)" = "$(stat -c %d:%i /proc/1/root/.)" ]] && echo "We are standalone!" || echo "We are chroot!"
We are chroot!
# findmnt -o target,source,fstype
TARGET SOURCE FSTYPE
/ /dev/sdb2 ext4
├─/boot/efi /dev/sdb1 vfat
├─/proc proc proc
├─/sys sysfs sysfs
├─/dev udev devtmpfs
│ └─/dev/pts devpts devpts
└─/run tmpfs tmpfs

3.3 - Bash prompt

Pour distinguer plus facilement les environnements, créer dans l'environnement chrooté, un fichier /etc/debian_chroot contenant un texte spécifique. Celui-ci sera ajouté entre parenthèses au début du prompt :

# echo "ssd" >/etc/debian_chroot

L'ancien prompt, de la forme :

root@host:/Chemin

devient (après fermeture et réouverture du shell ou du chroot) :

(ssd)root@host:/chemin

3.4 - Clôture du shell

# exit
exit

4 - Démontage du système de fichier

$ sudo umount /mnt/run
$ sudo umount /mnt/dev/pts
$ sudo umount /mnt/dev
$ sudo umount /mnt/proc
$ sudo umount /mnt/home
$ cd ..
$ sudo umount /mnt

Équivalent à :

$ sudo -- sh -c 'for i in {run,dev/pts,dev,sys/firmware/efi/efivars,sys proc;do umount /mnt/$i; done'

$ sudo umount /mnt
$ findmnt  |grep /mnt # Possibilité de spécifier le type de fichier -t ext4, etc...

On peut également utiliser cat /etc/mtab ou le résultat de mount etc....

$ lsof /mnt
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 12457 philippe cwd DIR 259,5 4096 2 /mnt
lsof 12999 philippe cwd DIR 259,5 4096 2 /mnt
lsof 13000 philippe cwd DIR 259,5 4096 2 /pnt
$ sudo fuser -k -i /mnt
/mnt: 3221rc 3315rc 3382rc 3599rc
Tuer le processus 3221 ? (y/N) y
Tuer le processus 3315 ? (y/N) y
Tuer le processus 3382 ? (y/N) y
Tuer le processus 3599 ? (y/N) y

5 - Dossier partagé

Dans le cadre d'un chroot, il peut-être intéressant de partager un dossier entre le système d'origine et le système chrooté.

Une fois le montage du système /dev/sdb1 effectué :

$ sudo mount --bind ./partage_origine /mnt/partage_chroot
$ sudo umount /mnt/partage_chroot

Le système chrooté peut alors être démonté.