Mahlzeit! UEFI bootet von einem USB-Stick vorzugsweise EFI/boot/bootx64.efi. Wenn man Debians Standardkernel dort hin kopiert, funktioniert das, weil die mit CONFIG_EFI_STUB=y gebaut werden. Dabei fehlen allerdings die initrd und die cmdline. Beides kann man zusammen mit dem Kernel in ein Unified Kernel Image (UKI) packen. Dazu gibt es eine Anleitung https://wiki.debian.org/EFIStub#Setting_up_a_Unified_Kernel_Image Die Methode mit objcopy baut allerdings auch linuxx64.efi.stub ein. Das ist gut und richtig für einen selbstgebauten Kernel, aber doppeltgemoppelt, wenn ich den originalen Debian Kernel benutzen will. Die Methode mit systemd-ukify macht das wahrscheinlich irgendwie richtig, aber ich würde es bitte gerne verstehen. Danke! Warum das attraktiv ist: Mit so einem UKI als bootx64.efi muss man genau 1 Datei an die richtige Stelle kopieren und die Kiste bootet - komplett ohne Bootloader, ohne efibootmgr, ohne EFI-Variablen und ohne Installation. Es sollte mit USB-Sticks und Festplatten genau gleich funktionieren und es ist angeblich die zuverlässigste Methode mit zweifelhaften UEFI-Versionen. was mir auch nicht geholfen hat: https://uapi-group.org/specifications/specs/unified_kernel_image/ https://wiki.gentoo.org/wiki/Unified_Kernel_Image https://wiki.archlinux.org/title/Unified_kernel_image https://www.reddit.com/r/archlinux/comments/1bwyz0i/uki_unified_kernel_image_and_directly_booting_it/ https://github.com/benthetechguy/debian-uki-hooks https://www.freedesktop.org/software/systemd/man/latest/ukify.html
Bei Firmen wie RedHat, Canonical und Microsoft muss man immer etwas aufpassen, wenn die was pushen. Eine Ramdisk / Initramfs konnte man schon immer in den linux Kernel mit einkompilieren. Wenn es kein Secure Boot gäbe, wäre das tatsächlich eine Vereinfachung, aber das ist nicht, worum es denen geht. Canonical und RedHat können ihren Kernel einfach mit dem MS key signieren, der in jedem amd64 PC hinterlegt wird. Aber du kannst das nicht. Du kannst einen Kernel mit eigenem Key selbst signieren, aber den musst du dann bei deinem System manuell hinterlegen. Bei manchen UEFI Firmware ist das (fast?) ein Ding der Unmöglichkeit. Das ganze ist also, zusammen mit den Lockdown LSM, und der Zukunftsmusik der Systemd Verity Geschichten (abriegeln des gesamten System (bzw. /usr) damit DU das nicht mehr ändern kannst [1]), ein Schritt dahin, dir die Kontrolle über dein System wegzunehmen. Das ganze soll wie ein Android oder iOS abgeriegelt werden. Die Agenda ist in etwa: * Lockdown LSM (fertig) * Unified kernel (in progress) * Verity (todo) * Bootloader nicht mehr anbieten / Signieren (braucht ja keiner mehr) * Secure Boot deaktivieren / Custom key erfassen, nicht mehr ermöglichen. (Optional, Nice to have) * Profit (Jetzt kontrollieren wir dein System Muhahahaha!) PS: Das pushen der unified kernels, so wie der Rest, ist auch auf Lennart Poetterings Mist gewachsen. Er arbeitet für Microsoft. 1) https://0pointer.net/blog/fitting-everything-together.html (Abschnitt "Hermetic usr")
:
Bearbeitet durch User
Bauform B. schrieb: > Die Methode mit objcopy baut allerdings auch linuxx64.efi.stub ein. Das > ist gut und richtig für einen selbstgebauten Kernel, aber > doppeltgemoppelt, wenn ich den originalen Debian Kernel benutzen will. Ja und nein: bootx64.efi enthält zwar 2 EFI-Stubs, aber den Kernel-eigenen kann man in diesem Fall nicht nutzen. Damit die Datei wie eine EFI application im PE32+ Format aussieht, muss ein EFI-Stub ganz am Anfang stehen. Der Kernel muss aber ganz am Ende stehen, weil der komprimiert ist und an Ort und Stelle entpackt wird. Stände der Kernel am Anfang, würden cmdline und initrd überschrieben werden. Unklar ist weiterhin, was linuxx64.efi.stub eigentlich macht. Das sind ca. 64KB, früher hat diese Funktionalität in 446 Byte gepasst! Und was passiert in der section namens ".sdmagic"? Und warum finde ich keine Alternative? Na gut, egal, Hauptsache das bootet. Man braucht nur dieses linuxx64.efi.stub, eine Textdatei mit der kernel cmdline in einer Zeile und ein Script:
1 | # make-uki |
2 | # funktioniert auch als User (nach einem chmod 644 /boot/initrd*) |
3 | # root muss nur noch den USB-Stick einrichten und /tmp/bootx64.efi kopieren |
4 | |
5 | VMLINUZ="/vmlinuz" |
6 | INITRD="/initrd.img" |
7 | CMDLINE="cmdline" |
8 | STUB="linuxx64.efi.stub" |
9 | |
10 | align="$(objdump -p $VMLINUZ | grep SectionAlignment | awk '{print "0x"$2}')" |
11 | echo algin vmlinuz $align |
12 | align="$(objdump -p $STUB | grep SectionAlignment | awk '{print "0x"$2}')" |
13 | echo align stub $align |
14 | align=$((0x1000)) |
15 | echo align $align |
16 | |
17 | osrel_offs="$(objdump -h $STUB | grep .text | awk '{print "0x"$3" + 0x"$4}')" |
18 | osrel_offs=$(($osrel_offs)) |
19 | osrel_offs=$((osrel_offs + $align - osrel_offs % $align)) |
20 | echo osrel_offs stub $osrel_offs |
21 | osrel_offs=$((0x1000200)) |
22 | echo osrel_offs $osrel_offs |
23 | |
24 | cmdline_offs=$((osrel_offs + $(stat -Lc%s "/usr/lib/os-release"))) |
25 | cmdline_offs=$((cmdline_offs + $align - cmdline_offs % $align)) |
26 | |
27 | initrd_offs=$((cmdline_offs + $(stat -Lc%s "$CMDLINE"))) |
28 | initrd_offs=$((initrd_offs + $align - initrd_offs % $align)) |
29 | |
30 | linux_offs=$((initrd_offs + $(stat -Lc%s "$INITRD"))) |
31 | linux_offs=$((linux_offs + $align - linux_offs % $align)) |
32 | |
33 | objcopy \ |
34 | --add-section .osrel="/usr/lib/os-release" \ |
35 | --change-section-vma .osrel=$(printf 0x%x $osrel_offs) \ |
36 | --add-section .cmdline="$CMDLINE" \ |
37 | --change-section-vma .cmdline=$(printf 0x%x $cmdline_offs) \ |
38 | --add-section .initrd="$INITRD" \ |
39 | --change-section-vma .initrd=$(printf 0x%x $initrd_offs) \ |
40 | --add-section .linux="$VMLINUZ" \ |
41 | --change-section-vma .linux=$(printf 0x%x $linux_offs) \ |
42 | "$STUB" "/tmp/bootx64.efi" |
Eigentlich sollten $align und $osrel_offs berechnet werden, aber so funktioniert es nicht. Mit den festen Werten geht's wenigstens in bookworm/amd64.
Also, so geht es auch nicht, war ja klar. linuxx64.efi.stub schreibt beim Booten irgendwelche EFI-Variablen zwecks Kommunikation mit systemd. Das mag man mögen oder nicht. Eine echte Alternative ist efibootguard; wahlweise gibt es einen Stub oder einen ziemlichen coolen Bootloader. Der hat etwas andere Prioritäten: kein Schnickschnack, der Rechner muss auf jeden Fall booten. Punkt. Auch nach einem missglückten Update. Dazu startet er den Hardware-Watchdog und benutzt 2 zusätzliche Partitionen nur für die Bootloader-Config und natürlich eine zweite System-Partition. Es funktioniert aber auch mit nur einer System- und der EFI-Partition. efibootguard ist relativ neu und sieht ziemlich gepflegt aus: https://bugs.debian.org/cgi-bin/pkgreport.cgi?archive=both;src=efibootguard https://packages.debian.org/trixie/efibootguard https://github.com/siemens/efibootguard/blob/master/README.md Disclaimer: Nein, ich bekomme kein Geld von Siemens.
Erstaunlich, wie über verkompliziert das ganze da wird. Beim Kompilieren konnte man ja schon immer die initramfs direkt in den Kernel packen: https://stackoverflow.com/questions/65868294/if-i-build-linux-kernel-from-source-does-it-contain-initramfs-inside-by-default#answer-65878026 Warum man jetzt, wenn man das nachträglich machen will, zusätzliche Loader / efi-stubs und was weiss ich was zusammenwursten muss, erschliesst sich mir nicht wirklich.
Daniel A. schrieb: > Beim Kompilieren konnte man ja schon immer die initramfs direkt in den > Kernel packen: ...und cmdline und Splash Image und vor allem efi-stub. So ein Kernel versteht sogar root=PARTUUID=$uuid, würde also auch ganz ohne initrd funktionieren. Ja, wenn man alles selber macht, ist alles ganz einfach ;) > Warum man jetzt, wenn man das nachträglich machen will, zusätzliche > Loader / efi-stubs und was weiss ich was zusammenwursten muss, > erschliesst sich mir nicht wirklich. Zusätzlich braucht man garnichts, insbesondere gerade keinen zusätzlichen Loader. Der Unterschied ist nur, ob man per make den Linker alle Einzelteile zusammenbauen lässt oder ob man es von Hand mit objcopy macht. Ein einzelner make Befehl sieht natürlich einfacher aus, innen drin passiert praktisch das gleiche. Ob man lieber so eine unified Datei benutzt oder vmlinuz und initrd per Bootloader lädt, ist doch Geschmackssache. Im Paket efibootguard gibt's die Zutaten für beide Varianten. Wer mehrere Kernel zur Auswahl mag, den betrifft das alles nicht, der nimmt sowieso grub. Eigentlich hatte ich nur eine Alternative zu grub gesucht. Für einen bootfähigen USB-Stick ist mir grub viel zu kompliziert. Mit so einem UKI müsste ich nur genau eine Datei kopieren. Mit dem Loader aus efibootguard muss ich 3 Dateien kopieren und die config erzeugen. Das finde ich dann doch einfacher als ein UKI zu bauen, das Ergebnis sieht auch vertrauter aus. Und das Fallback System mit Watchdog wäre für eine bestimmte Anwendung durchaus interessant.
Bauform B. schrieb: > Zusätzlich braucht man garnichts, insbesondere gerade keinen > zusätzlichen Loader. Der Unterschied ist nur, ob man per make den Linker > alle Einzelteile zusammenbauen lässt oder ob man es von Hand mit objcopy > macht. Ein einzelner make Befehl sieht natürlich einfacher aus, innen > drin passiert praktisch das gleiche. Das passt dann aber nicht zu: Bauform B. schrieb: > Ja und nein: bootx64.efi enthält zwar 2 EFI-Stubs, aber den > Kernel-eigenen kann man in diesem Fall nicht nutzen. Entweder es ist das selbe, und man kann den Kernel-eigenen nehmen, oder es ist es nicht, in dem Falls ist der Zusätzliche stub eindeutig ein weiterer Loader. Ob der jetzt in einer separaten Datei ist, oder nicht, spielt keine Rolle.
Daniel A. schrieb: > Entweder es ist das selbe, und man kann den Kernel-eigenen nehmen, > oder es ist es nicht, in dem Falls ist der Zusätzliche stub > eindeutig ein weiterer Loader. Debian baut einen ein, den kann man für manche Anwendungen nutzen, nur für diese nicht. Debian baut auch IPv6 ein, das nutzt auch nicht jeder. Auch der Kernel-eigene ist eine extra Datei, bevor der Linker alles zusammen baut. Bauform B. schrieb: > Damit die Datei wie eine EFI application im PE32+ Format aussieht, > muss ein EFI-Stub ganz am Anfang stehen. Der Kernel muss aber ganz > am Ende stehen, weil der komprimiert ist und an Ort und Stelle > entpackt wird. Stände der Kernel am Anfang, würden cmdline und > initrd überschrieben werden.
Bauform B. schrieb: > Stände der Kernel am Anfang, würden cmdline und initrd überschrieben werden. Offenbar geht es, wenn der Kernel selbst Kompiliert wird, und man dabei die initramfs direkt mit einbaut. Würde die objcopy Geschichte oben wirklich das selbe tun, wie beim selber bauen, kann es keinen unterschied machen, und es muss auch so gehen. Mit anderen worten, eine schöne Begründung von dir, nur ändert es nichts an meinem Argument.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.