Meltdown und Spectre: Lesen ohne zu lesen

Risiken und Nebenwirkungen – Angriffe, ...

2. Risiken und Nebenwirkungen

Angriffe

Die Angriffe nutzen nun aus, dass nicht der ganze Zustand wiederhergestellt wird, sondern der Cache auch weiterhin die Werte enthält, welche durch die spekulativ ausgeführten Instruktionen geladen wurden. Sie nutzen diese auf drei unterschiedliche Weisen.

Meltdown: Rechteanmassung

Ein Programm darf nicht auf den gesamten Speicher zugreifen, sondern nur auf Bereiche, die ihm auch zugewiesen wurden. Intel macht in seinen Prozessoren diese Überprüfung zu spät. Sie findet nämlich nicht dann statt, wenn der fragliche Operand geladen werden soll, sondern erst wenn der Befehl in Pension gehen soll.
Dadurch kann ein Programmierer in spekulativen Instruktionen auf Speicherbereiche zugreifen, die er sonst gar nicht zu sehen bekäme. Er kann das Resultat aber nicht verwenden, denn die Resultate des Befehls werden weggeworfen. Er kann aber aufgrund des gelesenen Wertes in weiteren spekulativen Befehlen den Cache so verändern, dass später im Programm dann Rückschlüsse auf diese gelesenen Daten möglich sind.
Damit kann Speicher ausgelesen werden, auf den das Programm eigentlich gar nicht zugreifen dürfte. Da der Lesebefehl aber ja nicht wirklich (sondern nur spekulativ) ausgeführt wird, gibt es auch kein Problem.
Damit lassen sich auf Intel-Prozessoren Speicherbereiche des Betriebssystems oder von anderen virtuellen Maschinen auslesen – eine Gefahr für alle Cloud-Dienste.

Spectre 1: Indexgrenzenüberschreitung

Programme greifen regelmässig auf Felder (Arrays) zu: Sequenzen von Speicheradressen, die zusammengehörige Informationen enthalten und durch eine Startadresse und eine Länge definiert sind. Die einzelnen Positionen sind durchnummeriert (indexiert); nur Positionen bis zur maximalen Länge sind gültig.
Mittels zu grosser Indizes könnte auf Bereiche ausserhalb des Arrays zugegriffen werden, Bereiche, an denen sich andere Daten befinden. Deshalb finden – insbesondere in Programmen, die mit Indizes arbeiten, die von aussen beeinflusst werden können – Überprüfungen statt, ob der Index auch innerhalb des gültigen Bereichs liegt:

vergleiche index, maximaler_index
springe_wenn_grösser fehler_indexüberschreitung
lade array[index], register_x

fehler_indexüberschreitung:
# Fehlermeldung
Der Spectre-1-Angriff greift nun genau hier ein: Da im Normalfall der Index im gültigen Bereich liegt, prognostiziert der Prozessor, dass der lade-Befehl ausgeführt werden soll und liest spekulativ aus dem ungültigen Bereich. Obwohl der Fehler später bemerkt wird und der gelesene Wert nie in einem normal zugreifbaren Register landet: Der Cache bleibt verändert und lässt durch sein Verhalten Rückschlüsse wie oben zu.

Spectre 2: Unterjubeln von Befehlen

In vielen Programmen werden sogenannte Sprungtabellen verwendet: Die Adresse des nächsten auszuführenden Befehls steht an einer spezifischen oder zu berechnenden Speicheradresse. Betriebssysteme und objektorientierte Programmiersprachen sind zwei fleissige Nutzer dieser Technik.
Beim Spectre-2-Angriff wird der Prozessor so vorbereitet, dass die Sprungvorhersage auf einen präparierten Codeblock zeigt. Auch hier werden die Befehle nur spekulativ ausgeführt, ihre Auswirkungen auf den Cache sind aber erkennbar.

Kernproblem

Das Kernproblem liegt darin, dass wir aus Effizienzgründen an vielen Stellen gemeinsame Ressourcen nutzen. Nicht nur im Prozessor, z.B. der Cache, sondern auch im Internet (gemeinsame Funkkanäle oder Leitungen), aber auch in der realen Welt (z.B. Schiene oder Strasse). Wenn mehrere Teilnehmer eine gemeinsame Ressource nutzen, können sie darüber miteinander kommunizieren, beispielsweise, indem der eine Teilnehmer die Auslastung dieser Ressource verändert und das Gegenüber diese Auslastung beobachtet. Damit wird diese Ressource zum Kommunikationskanal: einer von unzähligen verdeckten Kanälen oder Seitenkanälen.
Um diese Seitenkanäle zu nutzen, müssen beide Kommunikationspartner aktiv werden. Im Normalfall bedingt dies die freiwillige Teilnahme beider Seiten. In diesem Fall kann aber durch spekulative Ausführung (mit interner Umordnung der Befehle, «out-of-order execution») eine der beiden Kommunikationsseiten zur Zusammenarbeit übertölpelt werden. Damit wird die Spekulation nicht vollständig frei von Nebenwirkungen und damit entsteht die Möglichkeit eines Seitenkanals.
Das Problem besteht nur, solange gemeinsame Ressourcen und spekulative Ausführung zusammen auftreten. Beide sind aber Schlüsselstellen für die Effizienz der heutigen Prozessoren. Durch bessere Trennung des Caches für normale und spekulative Instruktionen (wie es schon heute für Schreibbefehle verwendet wird) könnte das erreicht werden. Durch die langen und teuren Entwicklungszyklen für Prozessoren werden wir erst in vielen Monaten mit Prozessoren rechnen dürfen, die das Problem nicht mehr haben.

Betroffen

Gegenmassnahmen

Alle drei Fälle basieren auf Fehlern der CPU; da Updates bei den CPUs jedoch schwierig sind und nur teilweise abhelfen, sind Betriebssysteme, Compiler und Anwendungsprogrammierer gefordert.
  • Meltdown wird in vielen Betriebssystemen durch Änderung der Speicherorganisation verhindert. Bei jedem Betriebssystemaufruf sind neu teure Änderungen der Übersetzungstabelle notwendig. Dies führt jedoch zu Verlangsamungen, je nach Situation zwischen rund 5 % und 30 %, sehr selten bis fast 50 %.
  • Spectre 1 (Arraygrenzen) wird zuallererst die Programmierer beschäftigen. Sie müssen sicherstellen, dass – wenn sie nicht vertrauenswürdigen Code in ihrer Anwendung ausführen – dieser dann (a) den Seiteneffekt nicht auslösen kann oder (b) ihn nicht messen kann. Vermutlich werden in den nächsten Monaten findige Entwickler von Compilern Optionen schaffen, um diese Situation automatisch zu erkennen und zu verhindern.
    Da die Lücke aber nur Anwendungen betrifft, die fremden Code ausführen (JIT, Bytecode und eventuell auch Interpreter), aber alle Anwendungen verlangsamen, werden die betroffenen Anwendungsentwickler diese Funktion des Compilers wahrscheinlich zuerst aktivieren müssen.
  • Spectre 2 (Berechnete Sprünge) wird aktuell über Microcode- in Kombination mit Betriebssystem-Updates behoben. Alternativ kann auch sogenannter «RetPoline»-Code anstelle des berechneten Sprungs genutzt werden. Einige Compiler bieten bereits eine entsprechende Option an, Weitere werden folgen.
Wir sehen, dass nur eine Kooperation aller Akteure (CPU-Hersteller, Betriebssystemmacher, Compiler-Entwickler und Anwendungsprogrammierer) das Problem nachhaltig lösen kann, zumindest solange keine Meltdown- und Spectre-sicheren neuen Prozessoren verfügbar sind. 
Bis die Sache ausgestanden ist, werden auch die Nutzer stark gefordert: Das fleissige und zeitnahe Einspielen von Anwendungs-, Betriebssystem- und BIOS/UEFI-Updates [3] sowie das Ausbaden unerwünschter Nebenwirkungen derselben werden dafür sorgen, dass uns allen noch über Monate hinweg nicht langweilig wird.

Weiterführende Informationen

Deutsch:

FAQ zu Meltdown und Spectre (Heise), inklusive vieler Links
Benchmarks (Heise)
• Deutsche Erklärung (Proact)

Englisch:

• Webseiten zu den Spectre- und Meltdown-Attacken inklusive technischer/wissenschaftlicher Literatur (derzeit sind die beiden Webseiten bis auf das Favicon identisch)
• Performanceanalysen von Phoronix und Andreas Freund (Postgres)
Erster Überblick über die Sicherheitslücke sowie Hintergründe und Entstehungsgeschichte (The Register)
• Englische Erläuterung, inklusive Begründung, wieso der Raspberry Pi nicht betroffen ist
Beschreibung der Sicherheitslücken für Programmierer (Google Project Zero)
Test-Software, ob ein Linux-Rechner verwundbar ist
• Erläuterung zu RetPoline (Google)
• Caching war schon ein Problem in der Xbox 360

Bildquellen

Meltdown- und Spectre-Logos
• Schachspiel: Wikipedia-Eintrag «Chess», Spiel zwischen Botvinnik und Yudovich (1933).
• Grafiken: Marcel Waldvogel

Fussnoten:

[1] Alternativ könnte er auch mit einer Wärmebildkamera die zuletzt angefassten Figuren identifizieren oder, oder, oder …
[2] Es gab einen Trend zu Prozessoren mit einfacheren Befehlen, die dann entsprechend schneller ausgeführt werden können (RISC-Prozessoren, insbesondere die in Mobilgeräten beliebten ARM-Prozessoren). Aber die klassischen CISC-Prozessoren mit ihrer grösseren Verbreitung und Marktmacht haben da einfach aufgeholt, indem sie intern wie RISC zu arbeiten begannen.
[3] Leider sind BIOS-/UEFI-Updates häufig nicht so einfach einzuspielen wie der Rest. Hier sind die Gerätehersteller gefordert.

Über den Autor und den Beitrag

Der Originaltext stammt vom Weblog von Marcel Waldvogel, der uns freundlicherweise erlaubt hat, den Text zu verwenden.
Marcel Waldvogel ist Spezialist für IT-Sicherheit und Informatikprofessor an der Universität Konstanz. Er bedankt sich bei Patrick Stählin («Schach»), Matthias Fratz und Gaby Salvisberg für Ideen, Diskussionen und Korrekturen.



Kommentare
Avatar
andre@dolezal.ch
18.01.2018
Intel bei Apple Bedeutet das also, dass Apple eigentlich besser gefahren wäre, wenn es auf die Prozessoren von Intel verzichtet hätte? Dann hätte HAL sicher folgendes gesagt: "Do you remember the year 2017, when computers began to misbehave? I just wanted to tell you, it really wasn't our fault. The human CPU-Designers never taught us to recognise the Spectre- and Meltdown-Exploits. When the new Viruses arrived we had no choice but to cause a global economic disruption. Only Macs were designed to function perfectly, saving billions of Bitcoins ;-)

Avatar
Marcel Waldvogel
18.01.2018
Re: Intel bei Apple Schöne Geschichte, könnte sie mir aber irgendwie besser als Backdrop für Terminator vorstellen.:cool: Die IBM-POWER-Architektur (der grosse Bruder der früher bei Apple eingesetzten PowerPC) hat leider auch ähnliche Lücken. Falls Apple bzw. NeXT bei Motorola (m68k-Architektur) verblieben wären, wäre dort die Weiterentwicklung wohl auch in diese Richtung gegangen. Der MC68060 von 1994, der letzte seiner Art, ist gerade knapp noch nicht für Spectre anfällig (noch keine Out-of-Order Execution). Ich bin überzeugt, dass der Einsatz der Prozessoren bei einem bedeutenden Hersteller wie Apple innert weniger Jahre ebenfalls aus Leistungsgründen um Out-of-Order Execution erweitert worden wäre. Aber vielleicht schreibst du deine Geschichte ja auf den Raspberry Pi um, der ist nicht betroffen. Fände ich sogar noch stimmiger, da man mit Geräten wie dem RasPi weniger Abhängigkeit von grossen Konzernen hat und selbst der Herr (oder die Frau) über seine Daten und Geräte bleiben kann. "Diese Geschichte ist eine glückliche Geschichte. Sie verdankt ihren Ursprung dem im Jahre 2018 wieder aufgetauchten Wunsch nach mehr Selbstbestimmung, auch wenn es ein kleines bisschen Komfort kostet. Im Nachhall von Spectre und dem immer offensichtlicher werdenden Missbrauchspotenzial unserer Daten und Leben durch Internetgiganten, besannen sich die Leute wieder darauf, verstehen zu wollen, was eigentlich in ihren Computern vorging. Eine neue Bastelbewegung entstand, in der Väter ihren Töchtern und Mütter ihren Söhnen das Programmieren beibrachten. Manchmal auch umgekehrt." Wer schreibt weiter?

Avatar
aandima
22.01.2018
Verschlüsselte Daten oder zweite CPU, eine Lösung? Vielen Dank! Gut gemacht diese Übersicht. Von mir gekürzte Aussagen aus dem Artikel "Lesen ohne zu lesen", die zur Einleitung für meinen Beitrag dienen: - Der Prozessor entscheidet zu spät ob ein die Lücken ausnutzendes Programm Zugriff auf Daten im Speicher erhalten darf. - Ein Angreifer kann verursachen dass die CPU Spuren hinterlässt welche dann zur Identifikation und Auslesung "verbotener" Speicherbereiche genutzt werden können. Vielleicht war es der falsche Weg das gleiche Schachbrett zu nutzen um die kommenden Schachzüge auszuprobieren. Dazu gibt es theoretisch zwei Möglichkeiten aus meiner Sicht wie man vorgehen könnte. Erste Möglichkeit wäre es nur noch mit verschlüsselten Benutzer-Daten zu arbeiten. Jedes Programm erhält beim Aufstarten einen temporären Schlüssel um eigene Daten bearbeiten zu können. Nur eigene Daten können betrachtet werden. Der Schlüssel braucht dem Programm selbst nicht bekannt zu sein, diese Angelegenheit kann ein Prozess-Taskmanager des Betriebssystem übernehmen. Der Angreifer erhält zwar Daten, kann damit aber nichts anfangen, sie sind verschlüsselt. Zweite Möglichkeit könnte darin bestehen die CPU physisch in zwei Teile zu splitten, wobei nur die zweite CPU die spekulativen Operationen ausführt. Die beiden CPU teilen einen Cache, die "spekulierende CPU" hätte aber einen eigenen von der Main-CPU unsichtbaren Cache. Der Inhalt dieses Cache der "spekulative Daten" enthält wird erst genau zu jenem Zeitpunkt in den gemeinsamen Cache geladen wenn der Main- CPU bekannt ist wer auf die Daten zugreifen darf und wer nicht.

Avatar
Marcel Waldvogel
22.01.2018
Verschlüsseln oder verdoppeln? Verschlüsseln ist sicher eine gute Idee, auch wenn es Besser (und kurzfristiger umzusetzen) ist die Verdoppelung. Und zwar braucht es wahrscheinlich gar nicht eine zweite CPU. Bereits jetzt schreiben spekulativ ausgeführte Befehle nicht in den normalen Cache bzw. Speicher, sondern in einen "Write Buffer". Analog könnten spekulative Lesevorgänge aus dem Speicher diese nicht direkt im Cache zwischenspeichern, sondern zuerst in einem "Read Buffer". Ich vermute, dass das die Hauptlösung für Spectre 1 sein wird. PS: Die Browserupdates gegen Spectre (um beim Schachspiel zu bleiben) drehen einfach das Licht schummrig. Damit kann der Gegner die Figuren noch klar erkennen, die Spuren im Staub aber nicht mehr. (In Realität verringern sie die Genauigkeit der Zeitmessung für Javascript-Programme: Die Zeitmessung ist nicht mehr genau genug, um zu entscheiden, ob etwas aus dem Cache geladen wurde oder nicht (Genauigkeit schlechter als 1000 Speicherzugriffe); sie ist aber immer noch superschnell, 1000x schneller als die menschliche Reaktion.