Einen neuen Zufallsmechanismus namens KARL hat OpenBSD-Gründer Theo de Raadt in der openbsd-tech-Mailingliste vorgestellt. Die Abkürzung steht für Kernel Address Randomized Link und verbindet die Bestandteile des Kernels in zufälliger Reihenfolge.

Das Ungewöhnliche dabei ist, dass das nicht beim Übersetzen des Kernels aus den Quellen passiert, sondern bei der Installation, bei jedem Upgrade und sogar bei jedem Neustart des Systems. Mit anderen Worten: Bei jedem Start erhält OpenBSD einen einzigartigen, neu zusammengewürfelten Kernel.

Ein Kernel ohne KARL

Um KARL zu verstehen, ist ein Blick auf das sonst übliche Vorgehen hilfreich: Der Compiler übersetzt alle zum Kernel gehörenden Quellcode-Dateien einzeln in Maschinencode. Zusätzlich gibt es den winzigen Bootstrap-Loader (Urlader, locore.S), der den eigentlichen Kernel in den Speicher lädt und startet. Es entstehen viele Objekt-Dateien mit der Endung .o, die – sehr entfernt – vergleichbar mit DLLs sind.

Zusammen mit notwendigen Daten hängt der Linker alle diese Objekt-Dateien, beginnend mit dem Bootloader, aneinander und schreibt sie in die Kernel-Datei (/bsd für den Single-Core-Kernel bei OpenBSD). Die Reihenfolge ist durch das config-Tool und weitere Hilfsdateien von OpenBSD bislang exakt festgelegt.

De Raadts berechtigte Kritik: Alle OpenBSD-Kernel eines Release sind absolut identisch. Wenn ein Angreifer, beispielsweise über einen kompromittierten Hypervisor mit OpenBSD als virtueller Maschine, auch nur einen winzigen Teil des Kernels identifizieren kann, kennt er automatisch alle anderen Einsprungpunkte für Kernel-Funktionen.

KARL sorgt für einen einzigartigen Kernel

KARL verhindert das, indem jeder Kernel durch seinen zufälligen Aufbau von Start zu Start einzigartig ist. Selbst den ausschließlich zum Laden des Kernels benötigten Bootloader-Teil entfernt das System nach Gebrauch aus dem Speicher. Ferner soll das Ganze mit einer nur minimalen Verzögerung beim Systemstart funktionieren.

KARL können Interessierte mit einem OpenBSD 6.1-CURRENT ausprobieren. (Bild: Michael Plura)

Den Kernel muss man nicht neu übersetzen, er wird mit einem Link-Kit aus seinen auf dem System vorhandene Objekt-Dateien zusammengestellt. Das geschieht über die neue reorder_kernel()-Funktion des Startskriptes /etc/rc. Das Diff hierfür ist überraschend klein und enthält keine Zeile C-Code. Da der neue Kernel während des Hochfahrens generiert wird, ist er für den darauf folgenden Systemstart relevant.

Unterschiede zum ASLR

Beim Address Space Layout Randomization (ASLR) weist das System Adressbereiche für Programme zufällig zu, was das Ausnutzen etwa von Pufferüberläufen erschweren soll. Bei der darauf basierenden Kernel Address Space Layout Randomization (KASLR) lädt Linux den immer identischen Kernel an zufällige Speicheradressen. KARL hingegen lädt einen zufälligen Kernel an eine identische Adresse.

Bei jedem Start einen neuen Kernel vorzufinden mag manchem Systemverwalter merkwürdig vorkommen. Es erinnert an die Mutations Engines von Viren, die so auf Signaturen basierende Virenscanner an der Nase herumführen. Bis auf das Aufwachen aus dem Hibernate-Modus funktioniert KARL aber in der Entwicklerversion OpenBSD 6.1-CURRENT problemlos und verlängert den Startvorgang kaum spürbar.

Update 10.7.2017, 13:20: Die Formulierung zur Auswirkung von ASLR auf Pufferüberläufe präzisiert. (fo)