C.6 Embedded Initramfs für signed IMA
... auf vielfachen Wunsch eines Einzelnen
Im anderen Artikel steht, dass für ein embedded initramfs die Kernel Option "Initramfs source file(s)" auf ein Verzeichnis stehen sollte, in dem schon alle Dateien drin sind. Es geht aber noch einfacher: Wir zeigen in dieser Kernel Option nur auf eine Datei mit einer Liste aller nötigen Dateien und der "make" macht wieder alles selbst (Nein, der delegiert das auch nur an die Tools).
Falls Du mal die Bezeichnung "UKI" gehört haben solltest. Ja, wir haben damit ein "Unified Kernel Image" in dem alles eingepackt ist:
- Kernel selbst
- Kernel Command Line
- Microcode und Firmware (für z.B. Intel Prozessor und Intel GPU)
- Initramfs
Damit können wir dieses Image signieren und eine schönen SecureBoot machen. DAS ALLES MIT BORDMITTELN und nicht so idiotisch wie z.B. hier:
https://wiki.archlinux.org/title/Unified_kernel_image
(Sorry, aber da musste ich jetzt mal ein bischen lästern)
Falls Du mal selbst ein embedded initramfs bauen willst ... das wichtigste was Du wissen musst: Selbst wenn Du alle Devices mittels "mount -t devtmpfs none /dev " erstellen läßt, musst Du /dev/console zwingend vorher manuell in Deinem initramfs drin haben. Deshalb MUSS die Zeile "nod /dev/console 0600 0 0 c 5 1" zwingend in die initramfs_list. Gemeinerweise wäre das nicht nötig wenn Du Dein initramfs als EXTERNES CPIO-Archiv bauen würdest. (Erklärung auf Englisch findest Du hier: https://wiki.gentoo.org/wiki/User:Pieti ... tramfs_.3F )
Was aber wirklich gezickt hat, war nicht das Bauen des initramfs, sondern IMA ... Ja, sobald man IMA aktiviert, ist es auch aktiv ... und verhindert das Laden von ausführbaren Programmen die keine Signierung (früher: Hash) haben. Diese werden ja in den erweiterten Attributen des File-Systems gespeichert ... leider hat ein initramfs keine erweiterten Attribute. Hahaha
Wenn Du das INIT Skript betrachtest, wirst Du feststellen, dass nach der Aktivierung von IMA (durch das Laden der Policy) nicht mehr das im initramfs enthaltene busybox aufgerufen wird / werden kann, sondern nur noch das auf unserer "echten" Root Partition ... weil das eben signiert ist. Das ist auch der Grund warum busybox zwingend statisch gebaut werden muss. Denn der Aufruf von /mnt/root/bin/busybox ist nicht in der Lage Libraries nachzuladen. Ja, ich habe das hier gelesen und dachte es wäre eine gute Idee:
https://wiki.gentoo.org/wiki/Talk:Early ... usybox_.3F
Ist aber leider nicht möglich. Das ist auch der Grund für den etwas merkwürdig aussehenden Aufruf von switch_root (am Ende von init). Glaub mir, jede andere Kombination führt zu einem Segmentation Fault und damit zu einer Kernel Panic ... rate mal wie ich zu dem 10. Post in A.2 gekommen bin ...
Falls Du mal dieses init File erweitern möchtest, solltest Du alles was Du einbauen willst VOR der Aktivierung von IMA machen.
Ich habe das mit meinem monolithischen Kernel Version 5.15.79 getestet, möchte das aber ausdrücklich noch als EXPERIMENTELL brandmarken. (weil das eben noch nicht lange genug getestet ist).
Voraussetzungen
Du hast einfach mal alles von C.2 bis C.5 gemacht (und verstanden), oder Du kannst alle Schritte gedanklich kombinieren
Vorbereitungen
0. Boote in den UNLOCKED Kernel und melde Dich dort als root an.
1. Das umkopieren des öffentlichen Schlüssels/Zertifikat nach /etc/ima ist zwar nicht zwingend nötig, aber damit ist es etwas aufgeräumter. Wir holen uns den Schlüssel nämlich später aus /etc/ima. Wenn Du einen anderen Namen verwendet hast musst Du das weiter unten anpassen oder Du renamest es gleich jetzt.
Code: Select all
# cp /etc/MY/efikeys/DB.cer /etc/ima/.Code: Select all
USE="-pam static static-libs" emerge -pvD busyboxÜberprüfe sicherheitshalber ob busybox wirklich statisch gebaut wurde:
Code: Select all
# ldd /bin/busybox
das Programm ist nicht dynamisch gelinkt4. Zuletzt entferne das bisherige Run-Skript aus dem Runlevel "boot" falls Du IMA bereits im Einsatz hattest:
Code: Select all
# rc-update del loadimapolicy bootErstellung initramfs
1. Diese Verzeichnisse und Dateien werden benötigt:
Code: Select all
mkdir /usr/src/initramfs
# nano -w /usr/src/initramfs/initramfs_list
=>
dir /bin 755 0 0
dir /dev 755 0 0
dir /etc 755 0 0
dir /lib 755 0 0
dir /lib64 755 0 0
dir /mnt 755 0 0
dir /mnt/root 755 0 0
dir /proc 755 0 0
dir /root 700 0 0
dir /sbin 755 0 0
dir /sys 755 0 0
dir /usr 755 0 0
dir /usr/bin 755 0 0
dir /usr/lib64 755 0 0
dir /var 755 0 0
nod /dev/console 0600 0 0 c 5 1
file /init /usr/src/initramfs/init 755 0 0
file /DB.cer /etc/ima/DB.cer 755 0 0
file /policy.conf /etc/ima/policy.conf 755 0 0
file /bin/busybox /bin/busybox 755 0 0
file /bin/cat /bin/cat 755 0 0
file /bin/keyctl /bin/keyctl 755 0 0
file /usr/bin/evmctl /usr/bin/evmctl 755 0 0
file /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2 755 0 0
file /lib64/libc.so.6 /lib64/libc.so.6 755 0 0
file /usr/lib64/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1 755 0 0
file /lib64/libkeyutils.so.1.10 /lib64/libkeyutils.so.1.10 755 0 0
slink /lib64/libkeyutils.so.1 /lib64/libkeyutils.so.1.10 777 0 0
file /usr/lib64/libimaevm.so.3.0.0 /usr/lib64/libimaevm.so.3.0.0 755 0 0
slink /usr/lib64/libimaevm.so.3 /usr/lib64/libimaevm.so.3.0.0 777 0 02. In diesem init-File musst Du eine Zeile editieren. Ändere NUR die ID selbst ! Benutze NICHT die PARTUUID von Deiner Root Partition. Lasse das UUID großgeschrieben.
Code: Select all
# nano -w /usr/src/initramfs/init
=>
#!/bin/busybox sh
### CHANGE THIS !
myrootpartition="UUID=c75f64b1-a1b1-4527-b996-4b4b9d24456c"
abend() {
echo "$@"
echo "You are now in a rescue shell."
busybox --install -s
exec /bin/sh
}
echo "Mounting proc, sys, devtmpfs and securityfs ..."
mount -t devtmpfs none /dev || abend "Error: mount /devtmpfs failed !"
mount -t proc none /proc || abend "Error: mount /proc failed !"
mount -t sysfs none /sys || abend "Error: mount /sysfs failed !"
mount -t securityfs securityfs /sys/kernel/security || abend "Error: mount /sys/kernel/securityfs failed !"
echo "Searching root partition device name of $myrootpartition ..."
rootdev=`findfs $myrootpartition` || abend "Error with findfs !"
echo "Found $rootdev as your root partition. Will mount it now ..."
mount -o ro $rootdev /mnt/root || abend "Error mounting root partition !"
### IMA Core routine begin
echo "Loading IMA certificate ..."
ima_id=$(/bin/keyctl newring _ima @u) >> /dev/null || abend "Error creating keyring !"
ima_key=`/usr/bin/evmctl import /DB.cer $ima_id` >> /dev/null || abend "Error importing certificate !"
/bin/keyctl setperm $ima_key 0x0b0b0000 >> /dev/null
/bin/keyctl setperm $ima_id 0x0b0b0000 >> /dev/null
echo "Loading custom IMA policy ..."
/bin/cat /policy.conf > /sys/kernel/security/integrity/ima/policy || abend "Error loading IMA policy !"
### IMA Core routine end
### Now IMA is activ and therefore a "busybox --install -s" would fail with "permission denied".
### This means, you cannot use abend() anymore here !
echo "Unmounting proc, sys, devtmpfs and securityfs ..."
/mnt/root/bin/busybox umount /proc /sys/kernel/security /sys /dev
echo "All done. Switching to real root."
exec /mnt/root/bin/busybox switch_root /mnt/root /sbin/initCode: Select all
General setup --->
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
(/usr/src/initramfs/initramfs_list) Initramfs source file(s)
[*] Support initial ramdisk/ramfs compressed using gzip
Built-in initramfs compression mode (Gzip) --->Code: Select all
Device Drivers --->
Generic Driver Options --->
-*- Maintain a devtmpfs filesystem to mount at /devEine Überprüfung schadet aber sicher nicht. Theoretisch kannst Du jetzt auch in Deiner Built-in Kernel Command Line den Paramter "root=... ro" raussschmeißen. Ist aber nicht nötig - der Kernel ignoriert das einfach.Selected by [y]:
- GENTOO_LINUX_UDEV [=y] && GENTOO_LINUX [=y]
4. Erstelle nun den neuen Kernel mit dem embedded intitramfs und installiere ihn als Deinen neuen EVERY-DAY-Kernel wie Du es sonst auch immer machst. Zum Beispiel:
Code: Select all
# mount /boot
# cd /usr/src/linux
# make -j8
# sbsign --key ........ --cert /etc/MY/efikeys/DB.crt --output /boot/EFI/Boot/bzImage.efi arch/x86/boot/bzImage
# rebootSonstiges
Falls Du mal dieses initramfs ändern möchtest (Dateien oder init) gibt es zwei Möglichkeiten bei einem "make" den Neubau zu erzwingen:
1. Du machst ein "make clean" vorher, ODER
2. Du löscht manuell all das:
Code: Select all
# cd /usr/src/linux/usr
# rm initramfs_data.cpio
# rm initramfs_data.o
# rm initramfs_inc_data
# rm built-in.a
# rm .built-in.a.cmd
# rm .initramfs_data.cpio.*
# rm .initramfs_data.o.cmd
# rm .initramfs_inc_data.cmd