- Définit l’initrd comme une unité de programme que le noyau interprète et exécute directement, et réinterprète Linux comme une sorte d’interpréteur
- Construit une distribution Linux récursive qui redémarre sur elle-même à l’aide de
kexec, base64 et cpio, l’initrd se réexécutant lui-même
- Si le script
/init est configuré pour afficher sa propre image cpio, on obtient un initrd auto-répliquant de type Quine
- Explique, via la structure d’exécution ELF,
ld.so et binfmt_misc, une hiérarchie d’interpréteurs qui se prolonge jusqu’au noyau
- En utilisant
kexec ou QEMU, il devient possible d’exécuter récursivement un autre Linux au-dessus de Linux de manière tail-récursive, étendant expérimentalement les frontières entre noyau, virtualisation et interpréteur
Rétro-ingénierie de rkx.gz et structure d’un initrd auto-récursif
- La commande
curl https://astrid.tech/rkx.gz | gunzip | sudo sh télécharge et exécute un script shell de 20 Mo encodé en base64
- Le script vérifie les privilèges root et la présence de
kexec, base64 et cpio
- Il décode les données base64 pour créer une archive cpio nommée
r, puis en extrait une image de noyau nommée k
- Il utilise
kexec pour charger et exécuter k comme noyau et r comme ramdisk
- À l’intérieur de
r.cpio se trouvent /bin, /init et le fichier k, où k est une image du noyau Linux 6.18.18 et /init un script shell
/init monte /proc, regroupe ensuite le système de fichiers courant en cpio dans /r, puis relance /k et /r via kexec
- On obtient ainsi une distribution Linux récursive qui redémarre continuellement sur elle-même
Le noyau Linux vu comme un interpréteur
- L’initrd n’est pas qu’un simple ramdisk de démarrage, mais peut être vu comme un programme que le noyau Linux interprète et exécute
- Comme
curl | sh ou python3 script.py, l’initrd est lui aussi une forme de programme d’entrée exécuté par le noyau
- Le noyau Linux fonctionne donc comme un interpréteur de l’initrd
- Cette structure ressemble à une optimisation de récursion terminale (tail-call optimization)
kexec ne remplace pas le noyau précédent en l’écrasant, mais charge et exécute le nouveau dans un nouvel espace mémoire
- Chaque noyau ne conserve pas l’état précédent et est remplacé par une nouvelle « stack frame »
Quine et auto-réplication de l’initrd
- Un Quine désigne un programme qui affiche sa propre source
- Si le script
/init exécute cat /r à la fin, il affiche un cpio identique à lui-même
- Dans ce cas, on obtient un Quine de l’interpréteur initrd de Linux
- Tous les fichiers existent en RAM sur
tmpfs, donc aucune E/S disque réelle n’a lieu
ELF, ld.so et la hiérarchie des interpréteurs
- Un exécutable ELF inclut dans son en-tête le chemin de l’interpréteur (
ld-linux-x86-64.so.2)
- Lors de l’exécution, le noyau lance d’abord
ld.so, puis ld.so charge les bibliothèques dynamiques de l’ELF avant d’exécuter le programme
- On peut donc aussi voir ELF comme une sorte de langage interprété
/bin/sh est interprété par ld.so, et ld.so est lui-même interprété directement par le noyau
ld.so étant un ELF lié statiquement, le noyau peut l’exécuter directement
- Cela forme ainsi le cas de base de la hiérarchie des interpréteurs
Exécution de CPIO via binfmt_misc
- Avec
binfmt_misc, il est possible d’exécuter via un interpréteur désigné des fichiers possédant des octets magiques spécifiques
- On peut enregistrer comme interpréteur un script qui exécute un CPIO comme initrd via QEMU
- QEMU démarre une machine virtuelle à l’aide du noyau et de l’initrd spécifiés
- En conséquence, l’interpréteur du fichier CPIO devient le noyau Linux lancé par QEMU
Interpréteurs récursifs et « la boucle la plus étrange »
- Un interpréteur fondé sur QEMU crée une nouvelle stack frame d’environnement Linux
- Dans cette structure, Linux en exécute un autre, et l’imbrication peut se poursuivre jusqu’aux limites de la mémoire
- En le remplaçant par un interpréteur fondé sur
kexec, on peut obtenir une exécution récursive de Linux avec optimisation d’appel terminal
- Si l’on enregistre
binfmt_misc dans /init puis qu’on configure l’exécution de /r,
on obtient un initrd qui s’exécute lui-même
/r est le prochain processus init au format CPIO et, lors de son exécution, il se réinterprète à nouveau
Conclusion
- L’initrd n’est pas un simple outil de démarrage, mais une unité de programme interprétée par le noyau Linux
- Avec
kexec et binfmt_misc, il devient possible d’exécuter Linux lui-même récursivement comme un interpréteur
- Cette structure est un concept expérimental qui brouille les frontières entre noyau, virtualisation, interpréteur et programme auto-répliquant
- Le code source associé est publié dans le dépôt GitHub ifd3f/rekexec
Aucun commentaire pour le moment.