Eine Hassliebe, denke ich.
UEFI und die Linux-Gemeinde
UEFI wird, zumindest in vielen Tutorials für verschiedene Linux-Distributionen, ziemlich zurückhaltend behandelt. Der Grund dafür dürfte darin liegen, daß UEFI bei OpenSource-Verfechtern unbeliebt ist. Und das ist auch nachvollziehbar: Inzwischen laufen unterhalb des Linux-Kernels neben der üblichen Gerätefirmware je nach System zusätzliche Betriebssysteme, die auch nicht all zu leicht loszuwerden sind.
Für aktuelle Intel-CPUs ist das zumindest die Management Engine, ohne die die CPU nichtmal anspringt und eben UEFI, der Nachfolger des BIOS, welches sich ja noch nach dem Laden des OS aus dem Speicher zurückzog.
Das macht es für Verfechter der "Meine Hardware, (ausschließlich) meine Software"-Sicht schwer, mit UEFI überhaupt warm zu werden, geschweige denn, darüber mal Tutorials zu schreiben.
Grundlagen
Soweit ich sie verstanden habe…
UEFI ist das "Unified Extensible Firmware Interface" und hat das alte BIOS inzwischen weitgehend ersetzt. Ein eventuell noch aufrufbarer "Legacy" Mode emuliert nur noch ein BIOS, dennoch wird auch im Legacy mode weiterhin das UEFI ausgeführt.
Im BIOS waren viele Dinge hart codiert - daher die Bedingung, daß es nur eine "aktive" Bootpartition pro Festplattenpartitionstabelle geben durfte; entsprechend, wo der Bootloader zu suchen und wie er aufzurufen war. Daher war BIOS auch Dateisystemagnostisch, solange ein passendes Binary mit einem ausführbaren Einsprungspunkt im richtigen Sektor der zu startenden Festplatte abgelegt war, konnte BIOS dies ausführen und dann die Gesamtkontrolle abgeben.
UEFI macht das anders.
Je nach Hardwarehersteller bietet UEFI Unterstützung für verschiedene Dateisysteme, mindestens aber wird FAT32 ("vfat") angeboten.
UEFI sucht auf den verfügbaren Datenträgern entweder nach aktiven Boot-Partitionen, für Datenträger mit BIOS ("msdos") Partitionstabelle oder nach speziellen EFI-Systempartitionen ("esp") bei den modernen GUID-Partitionstabellen ("gpt"), die bei Datenträgern oberhalb von 2TB Größe zwangsläufig genutzt werden müssen.
Im ersten Fall wird das alte BIOS-Bootloader-Verhalten verwendet, sprich: Das Binary im Bootsektor der aktiven Partition einer BIOS-partitionierten Festplatte gestartet.
Im zweiten Fall wird UEFI versuchen, das Dateisystem der ESP zu lesen und dort nach den konfigurierten Loadern suchen.
Wird der im UEFI hinterlegte Loader auf der ESP gefunden, wird er geladen und ausgeführt - was dann in aller Regel den regulären Start des Betriebssystems nach sich zieht.
Es kann aber auch sein, daß der Loader "einfach nur" ein Update der Firmware des unterliegenden Systems ausführt.
SecureBoot
Natürlich macht sich keine Firma überflüssig viel Arbeit und naben dem unangenehmen Umstand, daß schlicht absehbar war, daß die msdos-Partitionstabelle irgendwann die Festplattengrößen - es gibt heute SSDs im 2,5-Zoll-Format mit >15TB Speicherkapazität - nicht mehr würde handhaben können, gab es auch den Anspruch der Unterhaltungsindustrie, daß Computer doch bitte nur verifizierte Software ausführen mögen, um das Kopieren der hochauflösenden Hollywood-Blockbuster zu verhindern.
Die Geburtsstunde von SecureBoot.
Während BIOS einfach nur ein Stück Code von einem wohldefinierten Bereich der Festplatte lud und diesen dann zur Ausführung brachte, war UEFI plötzlich in der Lage, zu prüfen, was genau da eigentlich gerade geladen und ausgeführt werden sollte - und die Ausführung auch zu verweigern, wenn es zwar ausführbar ist, aber bestimmte Bedingungen nicht erfüllt.
Der Vorteil sollte - neben der Befriedigung der Paranoia der MPAA - auch sein, daß Nutzer, bzw. IT-Abteilungen, sicherstellen können, daß nicht unterhalb der wirklichen Betriebssystems irgendwelche Schadsoftware Passwörter und Festplattenverschlüsselungen abschnüffelt. - Nicht, daß UEFI und die noch darunter laufende Intel-ME nicht ihrerseits angreifbar und zu genau diesem Zweck nutzbar sind. Von den CPU-Bugs Spectre und Meltdown ganz zu schweigen.
An dem Punkt setzte dann der wirkliche Hass der Linux-Gemeinde gegen UEFI ein - weil nämlich ein PC mit aktiviertem SecureBoot die Zusammenarbeit mit den bisherigen Bootloadern stumpf verweigern würde. Die einzige Option, den Linux-Kernel in so einem System zu laden, wäre, eine gültige Signatur für den Bootloader zu bekommen, an die aber natürlich nicht so einfach dranzukommen ist - ganz zu schweigen von dem Fall, daß das Binary gar nicht direkt vom Hersteller bzw. Softwareautor kommt, sondern, wie z.B. bei Linux-from-Scratch oder Gentoo, schlicht selbst erstellt wird.
Tatsächlich ist es wohl gelungen, einen Stub signieren zu lassen, ein Stück Software, welches unveränderlich bleiben mußte, aber immerhin von UEFI mit aktiviertem SecureBoot ausgeführt werden würde und seinerseits dann den regulären Bootloader starten könnte.
Manche PC-Hersteller waren auch einsichtig und haben ihrem UEFI eine Option hinzugefügt, die ab Werk eingebauten SecureBoot-Zertifikate durch eigene zu ersetzen - womit der Nutzer/Eigentümer dann die Möglichkeit bekam, seine eigenen Schlüssel und Zertifikate zu erzeugen, im UEFI zu hinterlegen und seinen Linux-Bootloader bzw. Kernel selbst zu signieren.
Ende der Vorrede.
Linux-Kernel
Der Linux-Kernel bietet eine Option, das erzeugte Image mit einem EFI-Stub zu versehen. Im Prinzip bedeutet das nichts anderes, als daß das (komprimierte) Image für den Bootloader den erforderlichen Code enthält, um es für UEFI ausführbar zu machen.
Es reicht, einen solchen Kernel auf der ESP abzulegen und im UEFI als Bootoption einzutragen.
Damit könnte die Geschichte für den Linux-Kernel an sich schon zuende sein, wäre da nicht ein großes Aber.
Heutzutage übergeben Bootloader eine ganze Reihe an Parametern an den Kernel, manches davon weniger nötig als anderes, gebraucht wird aber immer das root-Device, die Festplattenpartition, in der der Kernel nach dem - ebenfalls zu spezifizierenden - Init-Binary sucht.
Interessant wird es, wenn der Bootloader eine Initramdisk mit übergibt, ein komprimiertes Dateisystem im RAM mit Binaries, die der Kernel braucht, um zum Beispiel eine verschlüsselte Festplatte zu öffnen - jedes Setup mit verschlüsseltem root-Dateisystem braucht eine solche Initramdisk.
Und natürlich die Kernelparameter, um die eigentliche Verschlüsselung nutzen zu können.
Alles kein all zu großes Problem - moderne Linux-Kernel können ihre eigene Ramdisk mit einkompilieren, ebenso statische Kernel-Parameter. Für Menschen mit entsprechender Detailkenntnis kein sonderlich großes Problem - Distributionen, die für möglichst große Flexibilität Initramdisks mit einer großen Zahl von Treibermodulen verwenden oder der Nutzerin die Möglichkeit geben möchte, den Kernel ausnahmsweise mit anderen Parametern zu starten, können darauf nicht zurückgreifen.
Bootloader
GRuB
Leider muß ich mich an dieser Stelle auf GRuB beschränken. Ich weiß, daß es andere Bootloader gibt und zum Teil sogar, wie sie heißen - ich habe mich nur nie mit ihnen auseinandergesetzt, geschweige denn, herausgefunden, wie ich die für ein UEFI-System benutze.
Eine UEFI-Installation von GRuB erschöpft sich darin, die ESP als /boot/efi zu mounten und grub-install --target=x86_64-efi /dev/to/esp aufzurufen.
Das wird sich bei anderen Bootloadern - sofern sie UEFI auch unterstützen - sicherlich ähnlich verhalten.
Vielleicht füge ich hier zu den anderen mal ein paar Absätze ein, wenn ich darüber stolpere.
SecureBoot - die Zweite
Mußte ja kommen.
Die einfachste Variante ist, SecureBoot abzuschalten.
Das bringt, dank des Dateisystems der ESP, einen großen Nachteil mit sich: Es gibt praktisch keine Möglichkeit, zu verifizieren, daß zwischenzeitlich, z.B. während der Laufzeit des Systems durch Schadsoftware, der Bootloader - oder das Kernel-Image - verändert wurde. FAT32 hat überhaupt keine Methoden, die darauf gespeicherten Daten mit auch nur rudimentären Zugriffsrechten zu versehen, verschlüsselt ist es auch nicht - ein Scheunentor für unbemerkte Zugriffe.
Außerdem könnte eine parallele Windows-Installation die Zusammenarbeit ohne SecureBoot verweigern - und jedes Mal im UEFI die Einstellung zu ändern ist auch nicht unbedingt praktikabel.
Eine Methode wäre es, einfach gar keine ESP im System selbst zu haben, sondern diese auf einem externen USB-Stick ständig bei sich zu haben.
Das ist einerseits im Schwimmbad etwas unpraktisch, weil die wenigsten Sticks wasserfest sind, andererseits auch einfach nicht praktikabel, wenn nicht für jeden Systemstart erst hingerannt werden soll.
Um eine gewisse Integrität des Bootloaders sichern zu können, kann wieder auf SecureBoot zurückgegriffen werden. Zumindest, wenn der Hersteller das Austauschen der SecureBoot-Zertifikate im UEFI vorgesehen hat.
Manche bieten den trivialen Weg, dies im Systemsetup während des Systemstarts zu tun: Die Zertifikatdateien liegen auf der ESP - oder einer anderen FAT32-Partition - und das Systemsetup kann sie von dort in den Flashspeicher der Firmware laden. Bei anderen Systemen muß dafür leider auf die etwas obskuren und nicht notwendigerweise sicheren Methoden der jeweiligen Linux-Distribution zurückgegriffen werden - mit dem Risiko, sich dabei das System zu bricken.
Dabei finden drei verschiedene Keys Verwendung: PK, der Platform-Key, eine Art Master-Schlüssel, vergleichbar einer Trusted Root-CA. KEK, der Key-Exchange-Key, ein Intermediate-Zertifikat, signiert durch den PK. Und db, eine ganze Sammlung an Keys, die die eigentlichen Bootloader signieren.
Im Normalfall liefert der Hersteller seine eigenen PK und KEK, mit denen er die Keys in der db signiert hat - darunter sind auch Revocation Keys, Schlüssel und Bootloader die für SecureBoot explizit gesperrt wurden.
Der Sinn und Zweck dieser ganzen Reihe von Keys ist die Handhabbarkeit auf Herstellerseite: Es gibt einen Hersteller-Root-Key (PK), der für alle Geräte des Herstellers identisch ist und der entsprechend besonders gesichert abgelegt ist.
Statt nun aber jeden Bootloader - und alleine Microsoft veröffentlicht da öfter mal einen neuen, durch die PKs aller Hersteller signieren zu lassen, hat sich Microsoft einen Key generiert, die die Hersteller ihrerseits signieren und signiert damit seine Bootloader. Sollte der Key bei Microsoft kompromittiert werden, kann er in der db des UEFI gelöscht oder als gesperrt markiert werden.
Der KEK dazwischen dient als Sicherungsschicht gegenüber dem PK - statt also den PK für jeden neuen Key in der Bootloader-Datenbank herauszuholen, wird dafür der KEK verwendet, der leichter zu ersetzen ist.
Sollen die SecureBoot Keys ersetzt werden, müssen ein neuer PK, ein neuer KEK und ein neuer "Bootloader-Signingkey" her, mit PK als selbstsigniertem Zertifikat, dem durch PK signierten KEK und dem durch den KEK signierten Bootloader-Signingkey.
Dafür gibt es Tutorials - das unterscheidet sich nicht wesentlich vom Anlegen einer CA und einer daran hängenden Intermediate-CA-Kette nach bestem X.509-Schema. Es finden sogar tatsächlich dieselben Dateiformate Verwendung.
Wer sich die gesamte Kette nicht zutraut - es genügt auch ein PK ohne KEK und dedizierten Bootloader-Signingkey.
Sind die Zertifikate erzeugt und im UEFI hinterlegt, kann jedes UEFI-Binary damit signiert werden.
Ist der Bootloader - oder der Linux-Kernel erstmal signiert, kann SecureBoot wieder eingeschaltet werden und zumindest der EFI-Stub des Linux-Kernels teilt dann im Kernel-Log auch mit, daß SecureBoot aktiv und nicht kompromittiert ist.
Passt die Signatur nicht (mehr), sollte das UEFI den Start des Bootloaders/Kernels verweigern.
Und ja, das geht auch mit den Bootloadern von Windows 10, die tatsächlich mehr als eine Signatur tragen dürfen.
Zumindest technisch. Leider.
Unglücklicherweise hat Microsoft, zumindet bis zur Build 1703 von Windows 10 entweder mit jedem Update den Bootloader ausgetauscht, oder irgendeine dieser obskuren Systemschutztechniken in Windows tauscht den Bootloader immer wieder gegen das nur einfach (und damit ungültig) signierte Original aus.
Es ist ein bißchen nervig, den Windows-Bootloader regelmäßig neu signieren zu müssen, weil das UEFI mit SecureBoot aber ausgetauschten Keys den Start von Windows mit dem Hinweis auf die ungültige Signatur des Loaders ablehnt…
efivars
Da UEFI auch nach dem Start des eigentlichen Betriebssystems noch läuft und auch für Resourcenzuteilung zumindest in Grenzen immernoch zuständig ist, kann und muss mit UEFI kommuniziert werden.
Unter Linux sind dafür die efivars - sowohl der Eintrag im sysfs, als auch die zugehörigen Tools - zuständig.
Darüber lassen sich Systemeigenschaften, wie das nun schon zum Erbrechen oft genannte SecureBoot oder, interessanter, die Bootreihenfolge auslesen. Und in manchen Fällen auch ändern.
Ebenfalls enthalten kann auch das Debug-Log des UEFI-eigenen Firmware-Updaters sein, und damit dem Betriebssystem eine Anzeige des Logs nach einem fehlgeschlagenen Firmwareupdate ermöglichen.
Prinzipiell wird damit das Systemsetup, welches während der Einschalttests eines PC aufgerufen werden kann, nahezu überflüssig.
efibootmgr
Eine der interessantesten Komponenten, die über efivars modifizierbar ist, sind die Boot-Variablen.
Hier können zusätzliche Einträge in der UEFI-Bootauswahl angelegt, geändert, gelöscht und an eine andere Position in der Reihenfolge verschoben werden.
Unter anderem können hier sogenannte "Capsules" eingetragen werden, UEFI-Binaries, die zum Aktualisieren der Firmware des Geräts dienen.
Und genau dafür benötigt der efibootmgr Schreibzugriff auf die EFI-Variablen.
Es sind also zwei verschiedene Dinge mit dem EFI-Stub und den efivars im Linux-Kernel: Keines bedingt das andere, aber es hilft, beides zur Verfügung zu haben.
Sollte mir irgendwann noch etwas Wesentliches einfallen, mache ich vermutlich einen Nachtrag…