Ein defektes System wieder zum Booten bekommen
Diese Beschreibung hier habe ich auf Grundlage meines Arch Systems erstellt. Sie ist aber prinzipiell übertragbar auf andere Distributionen. Sie kann für alle Arten von nicht startbaren Systemen helfen entweder das System zu reparieren oder seine wichtigen Daten aus dem System zu sichern.
Die Ausgangslage:
- Das Linux System ist Vollverschlüsselt -
- Die Rootpartition ist mit LUKS verschlüsselt
- /boot ist keine eigene Partition und liegt auf der komplett verschlüsselten Rootpartition
- Der Bootloader GRUB öffnet die verschlüsselte Partition und im Normalfall bootet er das System
- Die Rootpartition ist mit BTRFS formatiert
- Nach einem Update von Kernel und GRUB Version hängt sich das System nach der Eingabe des Passworts auf
Wir können das unser System nicht mehr booten.
Aufgeben? Aber Nein.
Für Fälle in denen das System nicht mehr startet sollte man ein anderes Bootmedium bereit haben (oder sich mal eben erstellen).
Das Bootmedium kann eine CDROM/DVD oder ein USB Stick aber auch eine externe Festplatte sein. Nachdem das temporäre System vom Bootmedium gestartet ist braucht man eine Shell.
Von der Shell aus führt man die folgenden Schritte aus:
- Man mounted die defekte Rootpartition in das System - z.B. unter /mnt
- Man überträgt für das System wichtige Mountpunkte in den Baumbereich der Rootpartition
- Man wechselt das Rootverzeichnis mit chroot - Dadurch kann man Aktivitäten so ausführen als hätte das System von der defekten Partition gestartet
- Man hängt UEFI mountpoints ein
- Dann installiert man aus dem Paketcache die vorherige Version der wahrscheinlich defekten Pakete
- Schließlich akualisiert/repariert man den Bootloader GRUB
- Dann die UEFI Mountpoints wieder entfernen
- Den chroot mit exit verlassen
- Alle weiteren Mountpunkte wieder entfernen
- Reboot
Man mounted die defekte Rootpartition in das System
Dazu muss man wissen wo sich dir Partition befindet. Hier helfen Kommandos wie:
- lsblk - zeigt alle dem System bekannten Laufwerke und deren Partitionen an
In der Ausgabe sollte das Laufwerk als nicht eingehängt auftauchen. Wenn man nicht gerade zig Laufwerke an seinen Rechner angeschlossen hat, sollte man das Ziellaufwerk schnell finden können. - blkid - zeigt alle Blockdevices im System an, mit Namen, IDs etc.
- [TODO]: Beispiele zeigen wie lsblk und blkid aussehen.
Idealerweise kennt man einen Teil der UUID der Partition. Aber das kann man nicht vorraus setzen.
Im Fall eines unverschlüsselten Systems macht man dann einen mount und ist mit diesem Punkt fertig.
Beispiel - wenn sich die gesuchte Partition unter sda3 befindet:
mount /dev/sda3 /mnt
Partition Verschlüsselt?
Tja, Verschlüsseln macht die Aufgabe einen Schritt komplizierter. Bevor man die Partition eingängen kann, muss erst die Verschlüsselung „geöffnet“ werden.
Dies geschieht mit dem Kommando cryptsetup.
cryptsetup open /dev/sda3 LOGISCHER_NAME_DER_GEOEFFNETEN_PARTITION mount /dev/mapper/LOGISCHER_NAME_DER_GEOEFFNETEN_PARTITION
Beim Aufruf von cryptsetup wird nach dem Passwort zum Entschlüsseln gefragt.
Ein Wort zu dem Label LOGISCHER_NAME_DER_GEOEFFNETEN_PARTITION. Dieser Name ist natürlich nicht frei wählbar. Vielmehr muss er mit dem identisch sein, der in der Partition in der Datei /etc/fstab gesetzt ist. Also eine Runde Öffnen, Einhängen, Nachlesen. Dann wieder Schließen und mit dem gefundenen Namen neu öffnen. Sonst gibt es später Probleme speziell, wenn man mit GRUB hantiert.
Man überträgt für das System wichtige Mountpunkte in den Baumbereich der Rootpartition
Wichtige Verzeichnisse, die im neuen Root Filesystem nicht fehlen dürfen, damit GRUB seine Einstellungen korrekt speichern kann:
- /dev
- /sys
- /proc
Und noch zwei weitere Verzeichnisse sind leider notwendig:
- /sys/firmware
- /dev/pts
Man kann alle zusammen in das neue Root unter /mnt einhängen mit der folgenden Kommandokette:
for x in dev dev/pts sys sys/firmware proc ; do mount -o bind /$x /mnt/$x ; done
Man wechselt das Rootverzeichnis mit chroot - Dadurch kann man Aktivitäten so ausführen als hätte das System von der defekten Partition gestartet
Das Kommando ein Programm in ein neues Rootverzeichnis unterhalb des eigenentlichen Roots „einzusperren“ lautet chroot.
Man führt am besten ein Shellprogramm aus. Das Kommando um eine bash Shell sieht dann so aus:
chroot /mnt /usr/bin/bash
Man hängt UEFI mountpoints ein
Dann installiert man aus dem Paketcache die vorherige Version der wahrscheinlich defekten Pakete
Schließlich akualisiert/repariert man den Bootloader GRUB
Dann die UEFI Mountpoints wieder entfernen
Den chroot mit exit verlassen
Alle weiteren Mountpunkte wieder entfernen
Reboot
Alles in einem Script
#################################################### # # Restoring a defective GRUB # # start a temporary arch OS from stick then # source the file and follow the instructions #################################################### # this is the partition logical name from /etc/crypttab LUKS_DRIVE=luks-a41aeaeae-1b9-431e-94a6-0032440889fd # # define mount options for subvol mounts MOUNT_OPT_ROOT=subvol=/@,defaults,noatime,compress=zstd MOUNT_OPT_HOME=subvol=/@home,defaults,noatime,compress=zstd MOUNT_OPT_CACHE=subvol=/@cache,defaults,noatime,compress=zstd MOUNT_OPT_LOG=subvol=/@log,defaults,noatime,compress=zstd # # Open the LUKS container - will ask for password interacively cryptsetup open /dev/nvme0n1p2 $LUKS_DRIVE # # Mount subvolumes into a temporary path mount -o $MOUNT_OPT_ROOT /dev/mapper/$LUKS_DRIVE /mnt mount -o $MOUNT_OPT_HOME /dev/mapper/$LUKS_DRIVE /mnt/home mount -o $MOUNT_OPT_CACHE /dev/mapper/$LUKS_DRIVE /mnt/var/cache mount -o $MOUNT_OPT_LOG /dev/mapper/$LUKS_DRIVE /mnt/var/log # # Add bind mounts for important system file systems: for x in dev dev/pts sys sys/firmware proc ; do mount -o bind /$x /mnt/$x ; done # # Give some hint text what to do inside the chroot environment, once there # echo "mount /dev/nvme0n1p1 /boot/efi">/mnt/bind_mount_efi.sh echo "mount -t efivarfs efivarfs /sys/firmware/efi/efivars">>/mnt/bind_mount_efi.sh echo "grub-install -v"> /mnt/fix_grub.sh echo "grub-mkconfig -o /boot/grub/grub.cfg">>/mnt/fix_grub.sh echo "umount /boot/efi"> /mnt/leave_chroot.sh echo "umount /sys/firmware/efi/efivars">> /mnt/leave_chroot.sh echo "exit">> /mnt/leave_chroot.sh # # This starts bash inside of the new root under /mnt: # chroot /mnt /usr/bin/bash # # inside of the bash execute above commands to fix GRUB or rescue data or do something else # # after leaving, cleanups: for x in /proc /sys/firmware /sys /dev/pts /dev /var/log /var/cache /home / ; do umount /mnt$x ; done cryptsetup close $LUKS_DRIVE