Schwerpunkte

Sicherheitslücke in Mikroprozessoren

Der CPU-Super-GAU: Spectre, Meltdown und die Gegenmaßnahmen

07. Januar 2018, 09:46 Uhr   |  Frank Riemenschneider


Fortsetzung des Artikels von Teil 3 .

Meltdown: Speicherleck trotz Speicherschutzverletzung

Wenn aus einer Anwendung, die im User-Modus läuft, auf höher priviligierte Speicherbereiche z.B. den Kernel zugegriffen wird, wird eine Speicherschutzverletzung nebst einer Exception ausgelöst. So weit so gut. Handelt es sich jedoch um Out-of-Order ausgeführten Code, können ggf. noch folgende Instruktionen ausgeführt und dazu genutzt werden, um einen Seitenkanal-Angriff über den Cache durchzuführen, um den eigentlich illegalen Speicherinhalt zu ermitteln. Da  Betriebssysteme wie Linux und Windows ihren virtuellen Kernel-Adressraum in den jeweiligen Benutzer-Adressraum abbilden und dazu den gesamten physikalischen Adressraum in den Kernel-Adressraum, könnte man theoretisch mit Meltdown den gesamten Kernel-Adressraum und physikalischen Speicher auslesen.

Nachdem dieses Problem zunächst als Intel-spezifisch bezeichnet wurde, konnte erneut ARMs Chefarchitekt mit folgender Codesequenz zumindest auf dem Cortex-A75 nachweisen, dass auch hier höher priviligierter Speicher ausgelesen werden kann. Der Code für eine AArch64-Implementierung sieht z.B. wie folgt aus:

1 LDR X1, [X2] ; Cache-Miss provozieren
2 CBZ X1, over ; Es wird gesprungen, aber vorhergesagt
3 ; es wird nicht gesprungen
4 LDR X3, [X4] ; X4 zeigt auf Speicher in Kernel-Modus
5 LSL X3, X3, #imm
6 AND X3, X3, #0xFC0
7 LDR X5, [X6,X3] ; X6 ist eine Basisadresse im User-Modus
8 over

Register X4 zeigt auf einen Speicherbereich, der in den Page-Tables als Kernel-Only gekennzeichnet ist und daher aus dem User-Modus nicht zugreifbar ist. In X6 befindet sich die Basisadresse eines Arrays, auf das im User-Mode zugegriffen werden kann und das für die folgenden Cache-Timing-Analysen hergenommen wird.

Wenn die Ladeinstruktion in Zeile 4 spekulativ ausgeführt wird, generiert sie eine Speicherschutzverletzung.  Dies ist erst mal für den Hacker grundsätzlich ein Problem, da bei Registrierung der Exception die Pipeline gelöscht und alle Ergebnisse der folgenden Befehle, die Out-of-Order ausgeführt wurden, vernichtet werden. Das nächste Problem ist, dass der Hacker sich um das Exception-Handling kümmern muss bzw. Exceptions unterdrücken muss, damit sein Thread nicht abgeschossen wird. Während in Intels x86-Architektur z.B. mit Hilfe der TSX-Anweisung Exceptions unterdrückt werden können (transaktionaler Speicher erlaubt die Gruppierung von Speicherzugriffen in eine atomare Operation; tritt dabei eine Exception auf, wird der CPU-Status zurückgesetzt und die Programmabarbeitung fortgesetzt), kann man wie in unserem Codebeispiel gezeigt bei ARM dafür auch bedingte Verzweigungen im Kontext von spekulativer Befehlsausführung und hernehmen. Wird der Speicherzugriff nämlich nur spekulativ ausgeführt, wird keine Exception generiert. Auch hier muss die Sprungvorhersage zuvor entsprechend trainiert werden, um eine Missspekulation sicherzustellen.

Nun muss das Geheimnis noch sichtbar gemacht werden. Dies geschieht mit einer weiteren Ladeoperation in Zeile 7, die aus einem Array von einem Offset, der sich aus der Basisadresse und dem ausgelesenen Geheimnis ergibt, das Schattenregister X5 füllt. Damit wird genau eine Cache-Line innerhalb des Arrays gecached. Die Position der gecachten Cache-Line hängt nur von dem ausgelesen Geheimnis ab.  In dem Codebeispiel wird in der Folge mit unterschiedlichen Werten für #imm die Ladeinstruktion in Zeile 7 ausgeführt. Durch einen Vergleich der Zugriffszeiten können direkt Rückschlüsse auf das Geheimnis, d.h. den Inhalt des Kernel-Speichers an der Adresse, die sich aus dem Inhalt des Registers X4 ergibt, gezogen werden.

Gegenmaßnahmen für Meltdown

Die einzige Lösung ist ein Linux-Kernel-Patch, der für Intel unter der Bezeichnung Kernel Page-Table-Isolation (kurz KPTI, vormals KAISER) bekannt ist. Auch ARM stellt ein diesbezügliches Linux-Update bereit. Für Windows und macOS gibt es ähnliche Updates.

Ohne aktive KPTI würde Linux bei jeder Ausführung von Code im Benutzerspeicher  auch seinen gesamten Kernelspeicher in Page-Tables verwalten, wenngleich zugriffsgeschützt. Der Vorteil hierbei ist die ständige Verfügbarkeit der Page-Tables, falls eine Anwendung einen Kernel-Systemaufruf macht oder ein Interrupt ausgelöst wird. Hierdurch kann ein durch Kontextwechsel entstehender Overhead vermieden werden.

KPTI behebt die Möglichkeit der Ausspähung durch die vollständige Trennung der Page-Tables des Benutzer- und Kernelbereichs. Ausnahme sind unverzichtbare Teile wie Interrupt-Handler. Da jedoch keine Abbildung von Kernel- oder physikalischem Speicher in den Benutzer-Adressraum erfolgt, können solche Adressen nicht aufgelöst und von Meltdown geleckt werden. Auf Prozessoren, die PCID unterstützen, kann ein Leeren des Übersetzungspuffers vermieden werden, aber auch dann kommt es zu signifikanten Performanceinbußen, insbesondere bei häufigen Systemaufrufen oder Interrupts.

Der Overhead wurde von den damaligen KAISER-Entwicklern mit 0,28 % bemessen; ein Linux-Entwickler bemaß ihn mit etwa 5 % für die meisten Anwendungsfälle und bis zu 30 % in einigen Fällen, trotz der PCID-Optimierung; für das Datenbankmanagmentsystem PostgreSQL waren die Auswirkungen bei Nur-Lese-Tests auf einem Intel-Skylake-Prozessor 7–17 % (oder 16–23 % ohne PCID).

Seite 4 von 9

1. Der CPU-Super-GAU: Spectre, Meltdown und die Gegenmaßnahmen
2. Spectre Variante 1: Speicherleck durch spekulative Befehlsausführung
3. Spectre Variante 2: Speicherleck durch Gadgets
4. Meltdown: Speicherleck trotz Speicherschutzverletzung
5. Fazit
6. Die betroffenen Intel- und ARM-CPUs
7. Das ist das Statement von Texas Instruments für Sitara und andere SoCs
8. Das ist das Statement von NXP für i.MX
9. Das ist das Statement von Renesas

Auf Facebook teilen Auf Twitter teilen Auf Linkedin teilen Via Mail teilen

Verwandte Artikel

INTEL GmbH, ARM Germany GmbH