Spectre und Meltdown erklärt (nicht nur) für Dummies
Die beiden Sicherheitslücken "Spectre" und "Meltdown" halten die Welt in Atem. Doch kaum einer hat die Grundlage des Problems verstanden. Das versuche ich im Folgenden ein bisserl zu ändern. Diesem Text liegt ein kurzes Video zu Grunde - siehe Ende des Blogposts (Screenshots daraus zur Auflockerei im Text).
Grundlagen
Cache
Ein Computer besteht (unter anderem) aus Speicher (da sind die Daten) und Prozessor (da werden sie verarbeitet). Moderne Prozessoren arbeiten eigentlich immer schneller als der normale Speicher die Daten liefern kann. Das wird umso schlimmer, je billiger der Speicher ist:
Von der Festplatte lassen sich die Daten am meisten Zeit, dann folgt das Ram (Faktor 100-1000 schneller) und dann der sogenannte "Cache" (davon gibt es meist mehrere Stufen - das übergehe ich hier aber geflissentlich).
Nur der ("first level") Cache fühlt sich einigermaßen in der Lage, die Daten ausreichend schnell in den Prozessor zu pumpen. Er hängt "zwischen" RAM und Prozessor und verwaltet sich durch den sogenannten Cachecontroller selbst. Die Idee hinter dieser Konstruktion ist, dass Daten, die bereits gelesen wurden, nochmal benötigt werden. Dann kann der Cache sie ohne Verzögerung liefern ohne auf langsameren Speicher zugreifen zu müssen.
Cache ist der teuerste und schnellste Speicher im Rechner. Festplatten hingegen der billigste (natürlich sind SSDs viel schneller, werden aber hier doch eher zu den "langsamen Speichern" gerechnet).
Speicherschutz
Einzelne Programme dürfen auf keinen Fall Daten anderer Programme lesen. So können Firefox und Konsorten natürlich nicht einfach auf den Passwort Manager o.Ä. zugreifen. Versuchen sie es doch, erkennt das der Prozessor aufgrund seiner Regeln und ruft eine Ausnahmebehandlung ("Exception") aus. Platt gesagt, schreit er um Hilfe.
Diese Überprüfung auf erlaubten Zugriff kostet Zeit (das wird später wichtig werden).
Speculative Execution
Ein Prozessor kann nicht jeden Befehl sofort ausführen. Deswegen ordnet er alle Anweisungen in einer Warteschlange an. Manche Befehle kann er auserhalb der Reihe ("out of order") bereits ausführen (bevor sie "dran" wären), da sie nicht mit den vorherigen zusammenhängen.
Oft muss in einem Programm aufgrund einer Berechnung eine Abzweigung genommen werden ("Branch"). In diesem Fall fängt der Prozessor an, zu raten, welchen Pfad das Programm wohl nehmen wird. Er spekuliert ("speculative Execution"). Liegt er richtig und wird dieser Branch benötigt, hat er das Ergebnis schon vorausberechnet. Hat sich die Vorhersage nicht bewahrheitet, so wird dieser Zweig verworfen.
In diesem "spekulierten Pfad" gibt es keine Überprüfung auf erlaubte Zugriffe - erst wenn der Pfad real wird, findet dieser Check statt (denn er kostet Zeit, wie wir vorher gelernt haben).
Die Lücke
Der folgende Trick spielt etwas "über die Bande" des Speichermanagements:
Voraussetzung ist, dass der Speicherort eines streng geheimen Datums bekannt ist (aber nicht darauf zugegriffen werden kann).
Erster Schritt:
Ein arglistige Prozess überzeugt den Computer davon, eine bestimmte Anweisungsfolge für wahrscheinlich zu halten und in den "predictive Branch" zu laden (er wird nur "mal auf Verdacht" ausgeführt). In dieser Verzweigung wird auf die verbotene Speicheradresse mit geheimem Inhalt zugegriffen und der Wert (beispielsweise "42") gelesen. Dieser Wert kann aber nicht aus seiner "virtuellen" Welt ausbrechen. Denn dann würde der Speicherschutz zuschlagen.
Zweiter Schritt:
Das Programm im "virtuellen Zweig" wird um eine Anweisung erweitert: sie verwendet den Wert (also 42) als Index für einen Zugriff auf einen erlaubten Speicher.
Beispiel: Der Piratenprozess (so nenne ich den Angreifer) darf auf Speicher von 1000-2000 regulär zugreifen. Der (nicht wirklich ausgeführte) Programmpfad in der "speculative Execution" hat den Wert "42" ausgelesen und liest als Folge die Speicheradresse 1000 + 42 = 1042 aus. Was da steht, ist vollkommen egal. Es geht nicht um den Inhalt, sondern um den Zugriff - über diesen kann der Speicherschutz übersprungen werden.
Dritter Schritt:
Zum Glück (oder doch eher Pech) hat der Cache Controller diesen Lesezugriff (auf Adresse 1042) mitbekommen und merkt sich den Vorgang. Der Piratenprozess weiß, dass der geheime Wert nur von 0-255 liegen kann (= 1 Byte in diesem Beispiel) und liest jetzt alle Adressen von 1000-1255 aus.
Der Trick:
Alle Speicherzugriffe dauern etwa gleich lang. Alle, bis auf einen. Der geht ratzfatz. Denn die Daten waren schon im Cache. Völlig egal, was in Adresse 1042 steht - der Zugriff auf diese Adresse erfolgte viel schneller als alle anderen und damit ist die "42" die Zahl, die vorher gelesen werden sollte.
Die Lücke
Die präzise auslesbare Zeit und das "halbe" Ausführen von Instruktionen ohne Überwachung erlauben diese (sehr langsame) Attacke. Man nennt das auch "Seitenkanalangriff", da eine Information benutzt wird, die auf einem Umweg erhalten wurde (platt ausgedrückt).
Werbung