6 Punkte von GN⁺ 2026-03-30 | 2 Kommentare | Auf WhatsApp teilen
  • initrd wird als Programmeinheit definiert, die der Kernel direkt interpretiert und ausführt, wodurch Linux als eine Art Interpreter neu gedeutet wird
  • Mit kexec, base64 und cpio wird eine rekursive Linux-Distribution gebaut, die sich selbst neu bootet; die initrd führt sich immer wieder selbst aus
  • Wenn das /init-Skript sein eigenes cpio-Image ausgibt, entsteht eine selbstreplizierende initrd in Quine-Form
  • Anhand der ELF-Ausführungsstruktur, ld.so und binfmt_misc wird erläutert, wie sich die Interpreter-Schichtung bis in den Kernel hinein fortsetzt
  • Mit kexec oder QEMU lässt sich auf Linux ein weiteres Linux in endrekursiver Form ausführen, wodurch die Grenzen zwischen Kernel, Virtualisierung und Interpreter experimentell erweitert werden

Reverse Engineering von rkx.gz und die Struktur einer selbstrekursiven initrd

  • Der Befehl curl https://astrid.tech/rkx.gz | gunzip | sudo sh lädt ein 20 MB großes base64-kodiertes Shell-Skript herunter und führt es aus
    • Das Skript prüft Root-Rechte und kontrolliert das Vorhandensein von kexec, base64 und cpio
    • Es dekodiert die base64-Daten, erzeugt daraus ein cpio-Archiv namens r und extrahiert daraus ein Kernel-Image namens k
    • Mit kexec werden k als Kernel und r als Ramdisk geladen und anschließend ausgeführt
  • In r.cpio befinden sich die Dateien /bin, /init und k; k ist ein Linux-6.18.18-Kernel-Image, /init liegt als Shell-Skript vor
    • /init mountet /proc, bündelt dann das aktuelle Dateisystem per cpio nach /r und startet anschließend per kexec erneut /k und /r
    • Das Ergebnis ist eine rekursive Linux-Distribution, die sich selbst fortlaufend neu bootet

Die Sicht auf den Linux-Kernel als Interpreter

  • initrd ist nicht nur eine einfache Ramdisk zum Booten, sondern kann als Programm verstanden werden, das der Linux-Kernel interpretiert und ausführt
    • Wie bei curl | sh oder python3 script.py ist auch initrd ein Eingabeprogramm, das vom Kernel ausgeführt wird
    • Daher fungiert der Linux-Kernel als Interpreter, der initrd interpretiert
  • Diese Struktur ähnelt einer Tail-Call-Optimierung
    • kexec überschreibt den vorherigen Kernel nicht, sondern lädt und startet ihn in einem neuen Speicherbereich
    • Jeder Kernel behält keinen vorherigen Zustand und wird durch einen neuen „Stack-Frame“ ersetzt

Quine und die Selbstreplikation von initrd

  • Ein Quine ist ein Programm, das sich selbst ausgibt
    • Wenn das /init-Skript am Ende cat /r ausführt, gibt es ein cpio aus, das mit ihm selbst identisch ist
    • In diesem Fall entsteht ein Quine des Linux-initrd-Interpreters
    • Da alle Dateien im RAM auf tmpfs existieren, findet keine tatsächliche Festplatten-I/O statt

ELF, ld.so und die Schichten des Interpreters

  • ELF-Binärdateien enthalten im Header den Pfad zum Interpreter (ld-linux-x86-64.so.2)
    • Bei der Ausführung startet der Kernel zunächst ld.so, und ld.so lädt anschließend die dynamischen Bibliotheken des ELF und führt das Programm aus
    • Daher kann auch ELF als eine Art Interpreter-Sprache betrachtet werden
  • /bin/sh wird von ld.so interpretiert, und ld.so wird direkt vom Kernel interpretiert
    • ld.so ist ein statisch gelinktes ELF und kann daher direkt vom Kernel ausgeführt werden
    • Dadurch entsteht der Basisfall der Interpreter-Schichtung

Ausführung von CPIO über binfmt_misc

  • Mit binfmt_misc lassen sich Dateien mit bestimmten Magic Bytes über einen festgelegten Interpreter ausführen
    • Beispiel für einen Registrierungsbefehl:
      echo ':cpio:M::\x30\x37\x30\x37\x30\x31::/path/to/my/script.sh:' > /proc/sys/fs/binfmt_misc/register
      
    • Mit dieser Einstellung lassen sich per chmod +x markierte CPIO-Dateien direkt ausführen
  • Über QEMU kann ein Skript, das CPIO als initrd ausführt, als Interpreter registriert werden
    • QEMU bootet eine virtuelle Maschine mit dem angegebenen Kernel und der angegebenen initrd
    • Dadurch wird der Interpreter der CPIO-Datei zu dem von QEMU gestarteten Linux-Kernel

Rekursive Interpreter und die „seltsamste Schleife“

  • Ein QEMU-basierter Interpreter erzeugt einen neuen Stack-Frame einer Linux-Umgebung
    • In einer Struktur, in der auf Linux ein weiteres Linux läuft, ist eine Verschachtelung bis an die Speichergrenze möglich
    • Ersetzt man dies durch einen kexec-basierten Interpreter, wird eine tail-call-optimierte rekursive Linux-Ausführung möglich
  • Wenn in /init binfmt_misc registriert und anschließend /r ausgeführt wird, ist eine initrd komplett, die sich selbst ausführt
    • /r ist der nächste Init-Prozess im CPIO-Format und interpretiert bei seiner Ausführung erneut sich selbst

Fazit

  • initrd ist nicht nur ein simples Boot-Werkzeug, sondern eine Programmeinheit, die der Linux-Kernel interpretiert
  • Mit kexec und binfmt_misc lässt sich Linux selbst rekursiv wie ein Interpreter ausführen
  • Diese Struktur ist ein experimentelles Konzept, das die Grenzen zwischen Kernel, Virtualisierung, Interpreter und selbstreplizierenden Programmen aufweicht
  • Der zugehörige Quellcode ist im GitHub-Repository ifd3f/rekexec veröffentlicht

2 Kommentare

 
github88 2026-03-31

Unwissen macht offenbar mutig … Solche Artikel sollte man besser vermeiden.

 
GN⁺ 2026-03-30
Hacker-News-Kommentare
  • Beim Lesen dieses Artikels litt ich unter zu vielen Missverständnissen
    Ein cpio-Archiv ist kein Dateisystem. Der Autor verwendet initramfs, das auf tmpfs basiert. Linux kann cpio nach tmpfs extrahieren. Ein Archiv aus Dateien und Verzeichnissen ist für sich genommen kein Programm
    Nur weil etwas ähnlich aussieht, ist es nicht dasselbe. Ein Binärprogramm wird auf der CPU ausgeführt, und wenn es einen Interpreter gibt, dann versteckt er sich in der Hardwareumgebung. Das liegt außerhalb des Zuständigkeitsbereichs des Kernels
    Um ein Shell-Skript auszuführen, braucht man eine Shell, die dieses Skript interpretiert. Der Autor lässt diesen Teil aus und verwechselt Kernel und Shell-Programm
    Linux kann auch ohne initramfs oder ramdisk kompiliert werden und trotzdem den Userspace eines Dateisystems ausführen
    Die Formulierung „Linux initrd interpreter“ ist wirklich eine falsche Beschreibung

    • Auch eine ELF-Datei ist nicht unbedingt schon für sich allein ein Programm. Manche ELF-Dateien sind dynamische Bibliotheken und haben keinen Entry-Point. So wie manche ELF-Dateien ausführbar sind, kann man auch manche CPIO-Dateien als ausführbar betrachten. Letztlich ist es ein ähnliches Konzept, ob ld.so ELF in den Speicher entpackt und den Entry-Point ausführt oder der Kernel initramfs entpackt und den Entry-Point ausführt
    • Die init-Datei in cpio ist das tatsächlich interpretierte Programm, und die übrigen Dateien dienen als Speicher, den dieses Programm verwendet
    • Binärprogramme laufen auf der CPU, aber die Programmdatei selbst ist eine Archivstruktur aus mehreren Sektionen. Die CPU kann die Programmdatei nicht direkt verstehen. Linux richtet den Adressraum ein, in dem das Programm laufen soll, und springt dann an die Adresse, auf die der Programmzähler zeigt. Die Metadaten-Sektionen von ELF definieren diesen Prozess
    • Wenigstens ist es kein von KI geschriebener Artikel
  • Ist nicht jedes OS in Kernel-Rechten eine Art Maschinencode-Interpreter?

    • Ich denke nicht. Das OS interpretiert nicht jede einzelne Instruktion selbst, sondern übergibt sie zur Ausführung an die CPU
    • Das OS ist eine Schnittstelle, die die Nutzung von Systemressourcen ermöglicht. Die CPU interpretiert den Maschinencode, und das OS kann der CPU sagen, was sie ausführen soll
    • In diesem Fall kann man es als Interpreter für CPIO-Dateien ansehen
  • Der Artikel ist in Ordnung, wenn man ihn als mentales Modell „Linux ist ein Interpreter“ versteht, aber wörtlich genommen ist er falsch
    Wenn man es nicht als Interpretation auf CPU-Befehlsebene betrachtet, sondern als Rolle des Kernels beim Orchestrieren von Ausführungsformaten wie ELF, Shebang-Skripten und initramfs, ist es plausibler. Die Verwirrung scheint daher zu kommen, dass zwei Bedeutungen von „Interpreter“ vermischt werden

  • Der Kernpunkt ist nicht, ob die Metapher stimmt, sondern dass sie zeigt, wie stark das Konzept von „Ausführung“ von der Umgebung abhängt

  • „Alles ist ein Interpreter?“

    • Ja, aber der Compiler ist die Ausnahme
  • Turings Theta Combinator

    • Ich bin mir nicht sicher, was das mit diesem Artikel zu tun hat. Mit Konzepten aus der funktionalen Programmierung bin ich nicht vertraut
  • In einem früheren Artikel der Serie sagte der Autor, er habe sein eigenes VPS-Image gebaut, weil er den Object Storage von Contabo nicht nutzen wollte
    Ich denke, irgendwo zwischen dem Extrem, 50 Stunden zu investieren, um 1,50 Dollar im Monat zu sparen, und dem anderen Extrem, 250.000 Dollar für Tokens auszugeben, gibt es einen Mittelweg.
    Wenn man sich die Infrastrukturkosten nicht leisten kann, könnte eher ein soziales Problem als mangelnde technische Kompetenz vorliegen. Sich darauf zu versteifen, Doom mit curl auszuführen, wirkt auf mich nicht produktiv

    • So war ich früher auch. 5 Euro im Monat für einen VPS waren mir zu teuer, also habe ich die Instanz beendet und das Root-Dateisystem auf dem Laptop meiner Mutter gesichert, bis ich wieder Geld hatte. Später habe ich auf einem Kindle Terminal IDE installiert und mit busybox und gcc herumgespielt. Danke an Spartacus Rex dafür, dass er den Anfang meiner Karriere möglich gemacht hat
    • Was der Autor sagte, war ein Witz. Der eigentliche Grund steht direkt im nächsten Absatz — „Ich hielt es für einen interessanten Trick und dachte, wenn ich ihn im Blog poste, lerne ich etwas, die Leser lernen etwas, und ich bekomme noch Internetpunkte dazu — ein Win-win
    • Auch wenn es für manche unproduktiv aussieht: Nischeninteressen zu genießen, ist wichtig für die psychische Gesundheit. Für mich mit ADHS ist das eher eine notwendige Aktivität
    • Die Aussage „Wenn du keine 1,50 Dollar zahlen kannst, bist du kein Profi“ ist seltsam. Professionalität wird dadurch definiert, dass man bezahlt wird, nicht dadurch, dass man Geld ausgibt
  • In man ld.so steht ausdrücklich, dass der dynamische Linker, der in der .interp-Sektion von ELF gespeichert ist, ausgeführt wird. Schon der Sektionsname ist interessant

  • Linux ist als programmierbare Schnittstelle sehr nützlich. Mit Windows geht das auch, aber Linux scheint dafür besser geeignet zu sein
    Ich finde die GUI unter Windows besser, aber auch GNOME oder KDE sind unbequem. Deshalb nutze ich fluxbox, icewm und manchmal xfce oder mate-desktop. Heutzutage bevorzuge ich eine einfache und schnelle Umgebung. Die meisten Aufgaben erledige ich über die Kommandozeile und beim Bearbeiten von Code

    • Wenn du eine schnelle und einfache Umgebung willst, ist die Kombination Sway + foot gut. Wenn man Workspaces mit Keybindings organisiert, kann man auch ohne Desktop sehr angenehm arbeiten
    • Dass die Windows-GUI besser sei, kann ich nicht unterschreiben. GNOME und KDE sind auch nicht toll, aber bei Windows kommt man nicht aus dem komplizierten WM von Microsoft heraus. Persönlich finde ich Interfaces aus der mpx/mux-Familie (z. B. 9wm, cwm, dwm) viel besser als die Xerox-Linie. Sie stehen Engelbarts Philosophie näher und sind insgesamt deutlich aufgeräumter