Bootfähigen USB-Stick für UEFI Secure Boot erstellen – 1. PreLoader der Linux-Foundation plus Gummiboot

Disclaimer: Dieses kleine Tutorial richtet sich an all jene, die entweder einen Admin-Stick mit verschiedenen Installern und Notfallsystemen erstellen wollen oder einfach eine Fingerübung suchen, um den Bootvorgang von UEFI Secure Boot besser nachvollziehen zu können. Die anfängliche Installation von LessLinux Search and Rescue kann nach und nach um weitere Linuxe erweitert werden. Als Bootloader verwende ich zunächst den unkomplizierten PreLoader.efi der Linux-Foundation in Kombination mit Gummiboot, möglicherweise folgt demnächst eine auf Shim (mit MOK) angepasste Anleitung. Auf den EFI-Boot von 32-Bit-Systemen möchte ich nicht eingehen, weil praktisch nur ältere Apple iBooks und MacMinis (CoreDuo, nicht Core2Duo) mit einem 32-Bit-EFI ausgeliefert wurden. Die paar Netbooks von Asus, die ebenfalls 32-Bit-EFI an Bord haben, sind in der Regel auf das CSM eingestellt (Compatibility Support Module = BIOS-Emulation zum Boot von MBR-Medien).

Hinweis: Auf dieses Tutorial folgt ein weiteres, das die hier gezeigte Konfiguration um GRUB erweitert (um 32-Bit-Systeme booten zu können) und eines, das erklärt, wie schließlich ein hybrider Stick entsteht, der auf MBR- und UEFI-Systemen startet. Wer aus dem dritten Tutorial das Optimum herausholen möchte, sollte eine dritte, 100 bis 200MB große, leere FAT32-Partition einplanen.

Wie bootet UEFI sicher vom Stick?

Der Vorgang von USB ist etwas einfacher als von Festplatte, zumindest wenn es sich um einen GPT partitionierten Stick mit einer einzigen FAT32-Partition handelt. In diesem Fall genügt es, eine Ordnerstruktur “BOOT/EFI” anzulegen, die den Bootloader “BOOTX64.EFI” enthält. Hintergrund dieser Vereinfachung ist wohl, dass es ermöglicht werden soll, alleine durch das Entpacken eines Zips mit den Bootdateien einen Stick bootfähig zu machen – aber das ist Spekulation, weder habe ich nachgeprüft welche UEFI-Implementierungen den einfachen Start unterstützen, noch habe ich getestet, ob in nennenswerten Stückzahlen USB-Sticks am Markt sind, die sowohl GPT als auch BIOS-MBR aufweisen.

In diesem Tutorial möchte ich mit dem simpelsten Bootmechanismus mit dem PreLoader.efi der LinuxFoundation als erste Stufe und Gummiboot als zweiter Stufe zum Start zum Start von 64-Bit-EFI-Kerneln beginnen. Zum Start von 32-Bit-Kerneln muss ein zwischengeschalteter GRUB genutzt werden, dafür wird es ein Follow-Up geben. Der Stick bekommt zwei Partitionen: Eine EXT4-Partition für die ISO-Images vorne und eine kleine Bootpartition, die Kernel, Initramfs und EFI-Boot-Dateien aufnehmen muss, hinten. Beachten Sie, dass die Bootdateien für ein LessLinux rund 50MB groß sind, die für ein Ubuntu etwas über 20MB – für zweimal LessLinux, zweimal Ubuntu und die EFI-Boot-dateien sind demnach 150MB einzuplanen.

Die Partitionierung

Zunächst gilt es, den Stick zu partitionieren. Damit keine Spuren von MBR, Partitionstabelle, GPT und möglicherweise alten Partitionsanfängen vorhanden sind, sollten die ersten vier Megabyte komplett genullt werden:

USBSTICK=/dev/sdx
dd if=/dev/zero bs=1M count=4 of=$USBSTICK

Zur Partitionierung kommt “parted” auf der Kommandozeile zum Einsatz:

parted $USBSTICK

Sie befinden sich nun in der Shell von Parted, hier gilt es, eine GUID Partition Table anzulegen:

Willkommen zu GNU Parted! Geben Sie 'help' ein, um eine Liste der verfügbaren Kommados zu erhalten.
(parted) mklabel gpt                                                      
(parted) print                                                            
Modell: Kingston DataTraveler 2.0 (scsi)
Festplatte  /dev/sde:  4039MB
Sektorgröße (logisch/physisch): 512B/512B
Partitionstabelle: gpt

Nummer  Anfang  Ende  Größe  Dateisystem  Name  Flags

(parted)

Als erste Partition erstelle ich eine einfache Linux-Partition, die der Gesamtgröße minus 150 MB entspricht, sie soll später Daten aufnehmen:

(parted) mkpart primary ext4 0 3890M

Inkorrektes Alignment kann man beim USB-Stick zumeist ignorieren (sollte man aber nicht bei SSDs und schnellen Platten). Es folgt die Bootpartition fürs EFI, diese muss FAT12/16/32 sein:

(parted) mkpart primary fat32 3890M 4039M

Diese zweite Partition bekommt jetzt das Bootflag gesetzt (eigentlich heisst dies bei GPT, dass der Typ auf EF00 gesetzt wird), danach betrachten wir das Ergebnis und schreiben die Partitionstabelle:

(parted) set 2 boot on                                                    
(parted) print                                                            
Modell: Kingston DataTraveler 2.0 (scsi)
Festplatte  /dev/sde:  4039MB
Sektorgröße (logisch/physisch): 512B/512B
Partitionstabelle: gpt

Nummer  Anfang  Ende    Größe   Dateisystem  Name     Flags
 1      17,4kB  3890MB  3890MB               primary
 2      3890MB  4038MB  148MB                primary  boot

(parted) quit

Die Prüfung mit

gdisk -l $USBSTICK

offenbart etwas mehr als “parted” (ich verwende parted, weil es sich auch gut scripten lässt):

GPT fdisk (gdisk) version 0.8.5

Partition table scan:
  MBR: protective
  BSD: not present
  APM: not present
  GPT: present

Found valid GPT with protective MBR; using GPT.
Disk /dev/sde: 7888896 sectors, 3.8 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): E12939B9-C620-435B-9E9B-27312CCBF9BC
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 7888862
Partitions will be aligned on 2-sector boundaries
Total free space is 2438 sectors (1.2 MiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1              34         7597656   3.6 GiB     0700  primary
   2         7598080         7886847   141.0 MiB   EF00  primary

Jetzt noch beide Partitionen formatieren und die Vorbereitung ist abgeschlossen:

mkfs.ext4 ${USBSTICK}1
mkfs.msdos -F32 ${USBSTICK}2

Installation des (Pre-)Bootloaders

Zunächst erstelle ich zwei Mountpoints für die Datenpartition und die Bootpartition und mounte beide. Wieder kommen Variablen zum Einsatz:

USBDATA=/tmp/usbdata
USBBOOT=/tmp/usbboot
mkdir -p ${USBDATA}
mkdir -p ${USBBOOT}
mount ${USBSTICK}1 ${USBDATA}
mount ${USBSTICK}2 ${USBBOOT}

Auf der Bootpartition entsteht nun die Ordnerstruktur für den Start unter EFI:

mkdir -p ${USBBOOT}/EFI/BOOT

In diesen Ordner installieren wir nun PreLoader.efi (als BOOTX64.EFI) und HashTool.efi der Linuxfoundation. Beide Binaries müssen signiert sein, bei diesen kommt demnach kein Selbstbau in Frage:

wget -O ${USBBOOT}/EFI/BOOT/BOOTX64.EFI http://blog.hansenpartnership.com/wp-uploads/2013/PreLoader.efi
wget -O ${USBBOOT}/EFI/BOOT/HASHTOOL.EFI http://blog.hansenpartnership.com/wp-uploads/2013/HashTool.efi

Wer möchte kann auch noch das KeyTool.efi installieren, ich findes es ganz praktisch, um MOKs (Machine Owner Keys zu verwalten. Ein Binary befindet sich im USB-Image von James Bottomley, ich habe es extrahiert:

wget -O ${USBBOOT}/EFI/BOOT/KEYTOOL.EFI http://cdprojekte.mattiasschlenker.de/Public/UEFI-Secure-Boot/keytool.efi

Im Prinzip würde der so erstellte Stick bereits booten, wenn auch nur bis zur Hash-Verwaltung.

Gummiboot als Loader

Als Loader der zweiten Stufe habe ich mich für Gummiboot entschieden, weil er 64-Bit-Linux-EFI-Kernel direkt starten, aber auch andere EFI-Binaries aufrufen kann. Ich habe versucht, Gummiboot auf einem Ubuntu 12.10 gegen die mitgelieferte und eine aktuelle Version der gnu-efi-Bibliothek zu kompilieren und bin gescheitert. Daher habe ich Gummiboot vom USB-Image von James Bottomley kopiert:

wget -O ${USBBOOT}/EFI/BOOT/LOADER.EFI http://cdprojekte.mattiasschlenker.de/Public/UEFI-Secure-Boot/gummiboot-bottomley.efi

Gummiboot benötigt nun einen Ordner für die Konfiguration, der die Bootmenüeinträge aufnimmt:

mkdir -p ${USBBOOT}/loader/entries

Die Konfigurationsdatei ${USBBOOT}/loader/entries/cclessli.conf (eingerückte Zeilen gehören zur Zeile “options”, bitte die Umbrüche entfernen):

title LessLinux Search and Rescue
linux    /ll64.efi
initrd   /ll64.img
options  ultraquiet=1 security=none skipcheck=1 quiet lang=de ejectonumass=1
    skipservices=|installer|xconfgui|roothash|firewall|ssh|mountdrives|
    hwid=unknown laxsudo=1 toram=0 uuid=c7e701f3-bd3c-494b-8395-1e5bdb513f41
    loop.max_loop=32 console=tty2 radeon.modeset=0 nomodeset

Achtung: Ein Bug in LessLinux erfordert es derzeit, die UUID der Partition anzugeben, auf der sich das ISO befindet (uuid=c6e...), ermitteln Sie diese mit dem Befehl blkid:

blkid  -o udev ${USBSTICK}1 
ID_FS_UUID=c7e701f3-bd3c-494b-8395-1e5bdb513f41

…und eine Konfigurationsdatei, um einfach das Hashtool aufrufen zu können, ${USBBOOT}/loader/entries/yyhashto.conf:

title Hashtool
linux    /EFI/BOOT/HASHTOOL.EFI

…und schließlich eine fürs Keytool, um Hashes und Schlüssel zurückziehen zu können, ${USBBOOT}/loader/entries/zzkeytoo.conf:

title Keytool
linux    /EFI/BOOT/KEYTOOL.EFI

Schließlich folgt noch die Konfigurationsdatei für den Gummiboot-Loader selbst, ${USBBOOT}/loader/loader.conf:

timeout 10
default cclessli*

Und nun das Lesslinux-Image

Damit wir wirklich ein bootfähiges System bekommen, dürfen wir das System-ISO nicht vergessen. Zudem müssen Kernel und Initramfs auf die EFI-Boot-Partition kopiert werden:

LESSLINUX=lesslinux-search-and-rescue-uluru-20130226-123741.iso
wget -O ${USBDATA}/${LESSLINUX} http://download.lesslinux.org/testing/lesslinux-search-and-rescue/${LESSLINUX} 
mkdir /tmp/lliso
mount -o loop ${USBDATA}/${LESSLINUX} /tmp/lliso
cp /tmp/lliso/boot/isolinux/l3800sf ${USBBOOT}/ll64.efi
cat /tmp/lliso/boot/isolinux/{initram,i3800sf}.img > ${USBBOOT}/ll64.img
umount /tmp/lliso

Der erste Start

Bitte nicht vergessen, den Stick zu unmounten:

umount $USBDATA
umount $USBBOOT

Nun wird es spannend: Stöpseln Sie den Stick an einen UEFI-PC mit aktiviertem Secure Boot an und starten Sie diesen. Wie bei BIOS-rechnern führt in der Regel F10, F12 oder ESC zum Bootmenü, Lenovo- (und wohl einige Medion-) Notebooks schalten Sie über die kleine Taste (“OneKey Rescue”) neben dem Powerbutton an. Der als BOOTX64.EFI abgelegte PreLoader.efi findet keinen hinterlegten Hash für “LOADER.EFI”, und startet “HashTool.efi”. Wählen Sie hier den zuerst den Hash des als “LOADER.EFI” abgelegten Gummiboots und dann den Hash des Linux-Kernels “ll64.efi” zur Aufnahme aus. Anschließend rebooten Sie das System und starten erneut vom Stick, jetzt erscheint das einfache Bootmenü von Gummiboot, in dem Sie LessLinux, HashTool.efi oder KeyTool.efi (um Hashes zurückzuziehen) auswählen können.

Uffz, geschafft. Bottomleys Gummiboot startet leider nicht Ubuntus signierte Kernel, hierfür muss als zweite Stufe ein GRUB her, doch dazu später mehr…