====== chroot zwischen verschiedenen Architekturen ====== Mittels ''[[linux:chroot]]'' in ein anderes Linux wechseln, um Reparaturen vorzunehmen, kann eine sehr praktische und zeitsparende Angelegenheit sein. Schwieriger wird es, wenn sich die Prozessorarchitektur des Zielsystems von dem aktuell verwendeten unterscheiden, da nahezu alle Programme als Binärdaten vorliegen, die die Instruktionen entsprechend für den jeweiligen Prozessor verwenden. Nehmen wir beispielsweise die Architektur ''x86_64'', auch bekannt als amd64, die 64 Bit-Variante des x86-Instruktionssatzes, welche auf nahezu jedem aktuellen Computer verwendet wird, und als Zielsystem ''armv7l'', ein Prozessor vom Typ ARMv7 mit 32 Bit, wie er beispielsweise beim Raspberry Pi 3 oder vielen Mobilgeräten Verwendung findet. ARM-Prozessoren mit 64 Bit weisen die Architektur ARMv8 auf. Würden wir einfach mittels ''chroot'' in ein solches ARM-System wechseln, würden die dort befindlichen für ARM kompilierten Binärpakete auf dem aktuellen Prozessor ausgeführt, der diese Instruktionen nicht kennt. Ergebnis wären Fehlermeldungen der Form > Kann die Binärdatei nicht ausführen: Fehler im Format der Programmdatei oder > Konnte execv nicht aufrufen (Fehler im Format der Programmdatei) > Fehler: Befehl konnte nicht korrekt ausgeführt werden Um dies zu umgehen, kann entweder eine [[arm:qemu_armv7_debian_vm|virtuelle Maschine mit einem ARM-System]] aufgesetzt werden, um die ARM-Instruktionen nativ verarbeiten zu können, oder man bedient sich statischer Binärpakete des [[http://www.qemu-project.org/|QEMU-Projekts]] für die verschiedensten Architekturen, was im Folgenden erklärt wird. ===== ARM Binärpakete emulieren ===== Um dennoch ARM-Instruktionen ausführen zu können, kann das Paket ''qemu-user-static'' verwendet werden, welches unter anderem ein statisch kompiliertes Binärpaket zur Emulation von ARM-Befehlen zur Verfügung stellt: ''qemu-arm-static''. Unter Arch Linux befindet sich das Paket im [[https://aur.archlinux.org/packages/qemu-user-static/|AUR]]. Sollte es häufiger vorkommen, fremde [[https://de.wikipedia.org/wiki/Executable_and_Linking_Format|ELF]] Binärpakete ausführen zu müssen, könnte es sich lohnen, einen Blick auf ''binfmt-support'' zu werfen, welches das ''binfmt_misc'' Kernel-Modul verwendet, um damit Interpreter für verschiedene Binärformate zu registrieren. Ich selbst registriere es später manuell. ==== chroot zu ARM für simple Aufgaben ==== Der zuvor erwähnte Fehler, dass das Binärformat von ARM vom aktuellen Prozessor nicht verstanden wird, lässt sich umgehen, indem ''qemu-arm-static'' in die ''chroot''-Umgebung kopiert und zum Ausführen von Anwendungen verwendet wird. Angenommen, ein ARM-System ist wie [[https://wiki.sash.pw/linux:chroot#chroot_in_ein_bestehendes_linux|hier]] beschrieben unter ''/mnt'' eingebunden und wir wollen dort einzelne Befehle ausführen können, dann benötigen wir die QEMU-Anwendung unter ''/mnt/usr/bin'': sudo cp $(which qemu-arm-static) /mnt/usr/bin Oder, wenn es unter dem Standard-Pfad installiert wurde: sudo cp /usr/bin/qemu-arm-static /mnt/usr/bin Um nun mittels ''chroot'' die Umgebung zu wechseln, müssen wir ''chroot'' mitteilen, was es ausführen soll: sudo chroot /mnt qemu-arm-static /bin/bash So landen wir mit einer Shell ohne Fehlermeldungen im gemounteten Verzeichnis des ARM-Systems. Alle Befehle, dir wir nun ausführen wollen, müssen mittels ''qemu-arm-static'' emuliert werden. Um uns beispielsweise mit ''uname'' Systeminformationen ausgeben zu lassen, müssen wir statt ''uname -a'' qemu-arm-static /usr/bin/uname -a aufrufen. Die Ausgabe könnte z. B. so aussehen: Linux my_host 4.9.11-1-ARCH #1 SMP PREEMPT Sun Feb 19 13:45:52 UTC 2017 armv7l GNU/Linux Auf diese Weise können diverse Reparaturen oder Korrekturen auf dem ARM-System durchgeführt werden. Diese Methode stößt jedoch an ihre Grenzen, wenn beispielsweise versucht wird, ein Shell-Skript auszuführen, da dort jeder Befehl entsprechend mit ''qemu-arm-static '' maskiert werden müsste. Ich wollte ein Kernel-Downgrade durchführen, da der neue Kernel, den ich installiert hatte, zu Boot-Problemen geführt hat. Dabei wird auch ''mkinitcpio'' ausgeführt, ein komplizierteres Bash-Skript, um alle nötigen Module am Kernel zu registrieren und eine "initial ramdisk" Umgebung ([[https://de.wikipedia.org/wiki/Initrd|initrd]]) zur Verfügung zu stellen, um den Kernel und alles, was das System benötigt, starten zu können. ==== Interpreter für fremde Binärformate registrieren ==== Der oben beschriebene Fall lässt sich einfach lösen, indem man seinem System mitteilt, wie verschiedene Binärformate interpretiert werden sollen. Dazu dient das ''binfmt_misc'' Kernel-Modul, dass über ''/proc/sys/fs/binfmt_misc'' eingesehen und manipuliert werden kann. Über das dortige ''register'' kann ein neuer Binär-Interpreter direkt im Kernel registriert werden, wodurch der Kernel weiß, wie in diesem Fall ARM-Instruktionen verarbeitet werden sollen, anstatt die eingangs erwähnten Fehler zu produzieren. Konkret funktioniert dies wie folgt: su echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-arm-static:' > /proc/sys/fs/binfmt_misc/register exit Nur der Systemadministrator darf einen neuen Interpreter registrieren, weswegen ''sudo'' nicht funktioniert. Danach wird dem Kernel mitgeteilt, an welchem File-Header einer ELF-Binary er das ARM-Binärformat erkennt und mit welchem Interpreter es ausgeführt werden soll. Zum Schluss verlassen wir die root-Shell wieder. Jetzt sollte die Datei ''/proc/sys/fs/binfmt_misc/arm'' erstellt sein, die die obigen Informationen enthält. Wechseln wir nun mittels ''sudo chroot /mnt'' das Wurzelverzeichnis, erhalten wir keine Fehlermeldungen, da der Kernel jetzt weiß, wie er die ARM-Instruktionen zu handhaben hat. Auch ein ''uname -a'' oder das Ausführen von Shell-Skripten funktioniert auf diese Weise ohne weiteres. ==== chroot für komplexere Aufgaben mit Einhängepunkten (mount / mtab) ==== Ist wie zuvor beschrieben das zu reparierende System eingebunden und ein Binärinterpreter für ARM hinterlegt worden, sollte es möglich sein, nahezu alle Aufgaben zu erledigen. In seltenen Fällen kann es jedoch sein, dass die mount points oder Einhängepunkte benötigt werden, speziell die Datei ''/etc/mtab''. In dieser Datei sind alle aktuellen Einhängepunkte des Systems zu sehen, welche auch bei der Eingabe von ''mount'' ausgegeben werden. Sollte dies der Fall sein, wird man Fehlermeldungen wie > could not open file: /etc/mtab: No such file or directory oder > could not determine filesystem mount points erhalten. Probleme dieser Art lassen sich beheben, indem die von Linux verwendeten und benötigten speziellen Verzeichnisse ''/dev'' (Geräteinformationen), ''/proc'' und ''/sys'' (Schnittstellen zum Kernel für die Kommunikation mit laufenden Prozessen und Kernel-Subsystemen) zur Verfügung gestellt werden. Diese virtuellen Dateisysteme können wie folgt eingebunden werden, dabei gehe ich wie weiter oben davon aus, dass das System unter ''/mnt'' gemountet wurde: cd /mnt sudo mount -t proc proc proc/ sudo mount --rbind /sys sys/ sudo mount --rbind /dev dev/ Anschließend kann wie gewohnt mit einem sudo chroot /mnt in das eingebundene Linux-System gewechselt werden. Sollte es nach Beendigung der Arbeiten beim Unmounten Probleme geben, da das Verzeichnis noch verwendet wird oder beschäftigt ist, kann statt beispielsweise einem sudo umount --recursive /mnt ein ''%%--force%%'' angehängt werden. Sollte auch dies nicht helfen, kann als Notlösung ein ''%%umount --lazy%%'' verwendet werden, sudo umount --recursive /mnt --lazy dabei werden die Einhängepunkte ohne Überprüfungen einfach freigegeben. Dies kann jedoch höchstwahrscheinlich zu Problemen auf dem aktuellen Host-System führen, weswegen nach der Verwendung von ''%%--lazy%%'' nach Möglichkeit so schnell wie möglich ein Neustart durchgeführt werden sollte. {{tag>linux chroot arm binfmt-misc mount mtab}}