Sicherheitslücke in Mikroprozessoren Der CPU-Super-GAU: Spectre, Meltdown und die Gegenmaßnahmen

Forscher u.a. von der TU Graz veröffentlichten Methoden, mit denen es gelingt, geheime Daten von mehr oder weniger allen superskalaren Prozessoren von Intel, AMD und ARM abzugreifen. Was steckt technisch wirklich dahinter und welche Gegenmaßnahmen sind möglich?

Alleine die Tatsache, dass Intels CEO Brian Krzanich Aktien im Wert von 24 Millionen Dollar Ende November 2017 zu Geld gemacht hat, und die Tatsache, dass Intel bereits Mitte 2017 von den Forschungsergebnissen um Spectre und Meltdown wusste, gab Anlaß zu Spekulationen: „Experten“ erklärten der Presse, dass jeder Prozessor ab dem Jahr 1995 ausgetauscht werden müsse, anders sei der Sicherheitslücke nicht beizukommen. Zum Teil wurden die Veröffentlichungen sogar mit dem VW-Dieselbetrug verglichen. Für Intel wäre dies natürlich ein finanzielles Deasaster und Krzanich müsste sich wohl tatsächlich Fragen bezüglich Insider-Handels gefallen lassen.

Was steckt aber wirklich hinter den beschriebenen Angriffsszenarien? Wir starten den Versuch einer sachlich-technischen Aufarbeitung.

Seitenkanal-Angriffe auf CPU-Mikroarchitekturen bereits 2007

Verwunderlich erscheint mir als allererstes, dass so getan wird, als würde man sich erstmals einer völlig neuen Art des Hackens bedienen, nämlich der Ausnutzung von Schwächen einer CPU-Mikroarchitektur. Tatsache ist, dass bereits im Jahr 2007 Forschungsergebnisse veröffentlicht wurden, die sich u.a. mit Seitenkanal-Angriffen über die Historie von Sprungvorhersagen bzw. den Sprungziel-Puffer beschäftigt haben. Auch das Ziehen von Rückschlüssen aus dem Timing bei Cache-Zugriffen ist bereits lange bekannt. Neu bei Spectre und Meltdown ist daher nur die Art, wie man an geheime Daten kommt, nämlich über die spekulative Befehlsausführung von superskalaren Prozessoren, nicht aber ein Angriff auf die CPU-Mikroarchitektur selbst. Behauptungen, dass von Hackern bisher „nur“ Schwachstellen in Software ausgenutzt wurden, und man nunmehr erstmals über eine Hardware-Lücke reden müsse, sind daher schlichtweg falsch.

Superskalare Prozessoren und die spekulative Befehlsausführung

Um die Ansätze von Spectre und Meltdown zu verstehen, ist es wichtig, die grundsätzliche Arichtektur von superskalaren, auf eine hohe Rechenleistung optimierte CPUs, zu verstehen – ein Beispiel hierfür ist der von uns im Detail analysierte Cortex-A75 von ARM. Dieser beinhaltet im Backend mehrere Pipelines für die Verarbeitung von Integer-, Gleitkomma- und Lade/Speicherbefehlen, die für einen möglichst hohen Durchsatz allesamt „unter Dampf gehalten“ werden wollen. Leider tut der CPU kaum ein Programm den Gefallen, die Instruktionen in einer Reihenfolge zu liefern, welche die Pipelines optimal für eine Parallelbearbeitung füttern. Besonders bitter aus Sicht einer CPU sind externe Speicherzugriffe und Abhängigkeiten von den geladenen Daten, was eine Blockade für hunderte Taktzyklen  bedeuten könnten, wenn es eben keine spekulative Befehlsausführung geben würde. Hierbei nimmt die CPU einen bestimmten Zustand, z.B. einen Sprung bei einer bedingten Verzweigung an und setzt an dieser Stelle mit der Programmverarbeitung fort, ohne zu wissen, ob der Sprung tatsächlich erfolgt. Genutzt werden hierfür u.a. sogenannte Schattenregister. Stellt sich später heraus, dass die Annahme falsch war und der Sprung gar nicht hätte erfolgen dürfen, werden die Ergebnisse verworfen und die CPU in ihren Zustand vor Beginn der spekulativen Befehlsverarbeitung zurückversetzt. Dies kostet natürlich Energie,  weshalb auf minimale Leistungsaufnahme optimierte CPUs wie ein ARM Cortex-M keine superskalare Architektur und Out-of-Order-Befehlsausführung aufweisen. Je besser die Sprungvorhersage ist, desto weniger oft muss verworfen werden, und desto höher ist der Datendurchsatz, deshalb investieren die Prozessordesigner soviel Zeit und Mühe in eine immer bessere Sprungvorhersage. Falls sich aber herausstellt, dass der Sprung korrekt war, wurde sehr viel Wartezeit gespart, weil der entsprechende folgende Code bereits abgearbeitet wurde.

Folgender Beispielcode illustiert die spekulative Befehlsausführung:

FADD r, temp1, temp2
FCMP test,r,:M
BNP test, 2F
LDA temp1,:Bmp:data

Lassen Sie uns einen Zeitpunkt t annehmen, nachdem die Gleitkommaddition FADD beendet ist und das Ergebnis vorliegt. Als nächstes werden in die Gleitkommapipeline der Vergleichsbefehl FCMP und in die erste Integer-Pipeline der Vergleichsbefehl BNP geladen. Letzterer kann nicht verarbeitet werden, weil das Ergebnis vom Gleitkommavergleich benötigt wird. Die CPU soll auf Grund ihrer Sprungvorhersage annehmen, dass BNP nicht verzweigt und beginnt in ihrer zweiten Integer-Einheit mit der Abarbeitung des LDA-Befehls. Wenn dieser abgearbeitet ist, ist auch der Vergleich fertig. Sollte sich herausstellen, dass der Sprung (nicht springen) falsch vorhergesagt wurde, muss der LDA-Befehl verworfen werden und die CPU in den Zustand vor dessen spekulativer Ausführung zurückgesetzt werden.