Zenbleed - Hardwaresicherheit in geteilten Infrastrukturen


Veröffentlicht am 30. Juli 2023 von Dominik Pataky

Hardware-Bugs in CPUs, Netzwerkkarten und weiteren Komponenten moderner Computersysteme sind leider nichts ungewöhnliches. Die Entwicklung dieser Produkte ist aufwendig, teuer und extrem komplex. Nicht umsonst ist insbesondere die Chipherstellung ein sehr überschaubarer internationaler Markt, mit Intel, AMD und Qualcomm als die wohl bekanntesten Vertreter dieser Sparte.

Alle Jahre wieder erscheint nun aber auch ein neuer Bug am Horizont, der bei genauerer Betrachtung roten Alarm in Security-Abteilungen erzeugt. Hierzu gehören z. B. Meltdown (2017), die Spectre-Familie (2017) und auch Rowhammer (2015, Angriffe auf RAM).

Seit dem 24. Juli 2023 sind nun Details zu „Zenbleed“ offiziell veröffentlicht. Tavis Ormandy et al von Google Project Zero entdeckten eine Möglichkeit, wie man in AMDs Zen2-basierten CPUs durch eine clevere Abfolge von Befehlen unbefugt Daten aus dem Prozessor auslesen kann. In der Tat ist das ein Implementierungsfehler, der sich glücklicherweise mit Updates beheben lässt. Für eine Liste von betroffenen Modellen, Patches und einer temporären Lösung („Chicken Bit“) verweise ich an der Stelle auf den zugehörigen Heise-Artikel.

Allerdings ist die Anfälligkeit für diesen Bug gleichzeitig ein Security-Incident, siehe CVE-2023-20593. Was dahinter steckt und welche Auswirkungen sich für die Nutzung der Cloud ergeben – in diesem Artikel schauen wir uns die Details an!

Update 23. August: Es gibt mittlerweile einen Part 2: Hardwaresicherheit, Part 2: Collide+Power, Inception, Downfall

Zenbleed? Branch prediction? Register?

Jetzt wird es kurz technisch, für die weitere Fachanalyse gerne zum nächsten Abschnitt springen.

Um die technischen Details hinter dem Bug zu erläutern, greife ich auf Tavis’ Post auf der oss-security-Mailingliste zurück :

The vector register file (RF) is a resource shared among all tasks on the same physical core. The register allocation table (RAT) keeps track of how RF resources are assigned and mapped to named registers. However, no RF space is needed to store a register with a zero value - a flag called the z-bit can simply be set in the RAT.

If the z-bit is set speculatively, then it would not be sufficient to unset it again on branch misprediction. That’s because the previously allocated RF space could have been reallocated between those two events. That would effectively be a UaF. We have discovered that this really can happen under certain specific conditions. Specifically, an instruction that uses merge optimization, a register rename, and a mispredicted VZEROUPPER instruction must enter the FP backend simultaneously.

Im zugehörigen Blogpost sind Grafiken enthalten, mit denen man die Angelegenheit verständlicher erfassen kann.

Zusammengefasst passiert folgendes: Wenn Programme auf einer CPU ausgeführt werden, landen in den sog. Registern die laufenden Daten dieser Programme. Wollen wir z. B. 1 + 2 berechnen, so wird in Register A die 1 und in Register B die 2 geladen und dann eine SUMME-Funktion aufgerufen. Die Hardware hat dann implementierte Schaltkreise, um diese Funktion auszuführen und das Ergebnis wird in ein weiteres Register geschrieben.

Moderne Prozessoren rechnen aber nun nicht nur auf dem Level von Grundschulmathematik, sondern sind unfassbar komplexe Multitasker, die mit Hilfe von vielen schlauen Algorithmen ihre Performance bis ans physische Limit optimieren. Zu diesen Algorithmen gehört die speculative execution mit der Methode der branch prediction. Im Prinzip macht die CPU an dieser Stelle nichts anderes, als möglicherweise benötigte Programmabläufe schon mal auf Verdacht auszuführen.

Nehmen wir als Beispiel folgenden Code (Python, nicht optimiert, nur zur Anschaulichkeit):

1a = 4
2b = 7
3if isPrime(a):
4    if isPrime(b):
5        return 1
6return 0

Das Programm enthält zwei Integer, die jeweils darauf geprüft werden, ob sie Primzahlen sind. Ist das bei beiden der Fall, gibt das Programm 1 zurück, ansonsten 0. Die CPU führt, nach Laden der Integer, isPrime(a) aus und gelangt bei Erfolg zu isPrime(b). Auch das wird dann ausgeführt und ausgewertet. Passt alles, wird 1 als Rückgabewert gespeichert und das Programm verlassen.

Aber wäre es nicht schneller, wenn ein anderer Kern schon mal vorab isPrime(b) berechnet, und wir verwenden das Ergebnis, wenn wir tatsächlich in Zeile 4 landen? Genau das macht speculative execution! Da Prozessoren mehrere Kerne besitzen, können mehrere Berechnungen gleichzeitig durchgeführt werden. Das beschleunigt viele Programme enorm und verhindert auch, dass ein rechenintensives Programm die anderen aufhält.

Wenn ein Prozessor auf Verdacht hin eine Berechnung durchführt, aber das Ergebnis nicht gebraucht wird, setzt der Prozessor den Stand auf den ursprünglichen Zustand vor der verworfenen Berechnung zurück. Hier kommen die Register ins Spiel, da diese zum State gehören. Der RAT erfasst den Zustand der Register und setzt, wenn ein Register den Wert 0 enthalten soll, das z-bit flag. Die dahinterliegenden Daten können dann verworfen werden, da auf sie nicht mehr im RAT verwiesen wird.

Und nun kommt das Problem: Wie revertet man einen destruktiven Vorgang wie das Freigeben von Speicher? Tja, Zen2 jedenfalls macht es so, dass die Einträge im RAT wieder auf die „ursprünglichen“ Inhalte zeigt.. – Welche mittlerweile aber neue Daten enthalten, weil die Register freigegeben wurden. Man sieht schon, hier wird nur halb sauber gearbeitet. Das Ergebnis ist am Ende der Zugriff auf Daten, die von anderen Programmen erzeugt und in die freigewordenen Registereinträge geladen wurden.

Zenbleed zeigt, dass genau dieser Zustand routiniert provoziert werden kann. Der Bug wird zum Security-Issue.

Bugs, die zum Security-Issue werden

Die Ausnutzung des Zenbleed-Bugs ermöglicht uns also, Daten aus der CPU auszulesen, die wir nicht selbst erzeugt haben. Sie müssen also von anderen Programmen stammen, die die selbe CPU verwenden wie unsere Programme. Die Schutzziele Vertraulichkeit und Autorisierung werden somit verletzt.

Einerseits ist die Vertraulichkeit des Programms, dessen Daten ausgelesen werden, ausgehebelt. Andererseits umgeht das Angreifer-Programm die Autorisierung, nur auf eigene Daten zugreifen zu können. Insbesondere die Verletzung der Vertraulichkeit stellt das Hauptproblem von Zenbleed dar. Wie kann ich mich hiervor schützen?

Besonders die Reichweite der Auswirkungen des Bugs sollte einige Security-Verantwortliche wach werden lassen und die Dringlichkeit von Patches hervorheben:

The practical result here is that you can spy on the registers of other processes. No system calls or privileges are required. It works across virtual machines and affects all operating systems.

Daten aus CPU auslesen. Keine speziellen Berechtigungen notwendig. Funktioniert auch über virtuelle Maschinen hinweg, auf allen Betriebssystemen. Ups. Es ist vermutlich klar, dass wir hier zwar technisch von Bugs sprechen, jedoch der Impact sicherheitskritisch sein kann!

Im folgenden Video ist eine Demo von Zenbleed zu sehen. Gezeigt ist die VM-übergreifende Datenauslese auf einem AMD-Prozessor. Links im Bild ist eine VM mit sensiblen Daten, rechts die VM, die mit Zenbleed angreift. Das Resultat ist ein erfolgreicher Abgriff eines Passworts (hier: Authorization Bearer-Token).

Computing in der Cloud bedeutet Teilen von Hardware

Womit wir zum letzten Aspekt in diesem Artikel kommen: Hardware in der Cloud.

Ja, tatsächlich, man mag es kaum glauben: Auch die Cloud wird auf echter Infrastruktur betrieben! Man möge mir den Sarkasmus verzeihen, denn die Cloud ist durchaus für viele eine Abstraktion weg von physischen Servern. Es ist deshalb aus meiner Sicht wichtig, diese Eigenschaft nicht aus den Augen zu verlieren.

Im Kontext von Zenbleed zeigt sich nun ein Hauptproblem geteilter Infrastruktur: Die unterliegende Hardware wird zwischen mehreren Kunden geteilt. Im Falle eines solchen Bugs, wie hier in AMD-Prozessoren (betrifft insbesondere EPYC-Server-CPUs), kann daher die eigentlich sichere Umgebung durchbrochen werden. Es können über virtuelle Maschinen hinweg Daten ausgelesen werden. Die Grenzen von Sandboxing verschwimmen. Es ist auch nicht nachvollziehbar, ob die eigenen Bytes vielleicht mitgeschnitten wurden.

Darüber hinaus: Wer ist letztlich verantwortlich? Entsprechend dem Modell der „Shared Responsibility“ (siehe Azure und AWS) gilt in Cloud-Umgebungen immer: Hardware ist in der Hoheit des externen Dienstleisters. Nur On-Premise erlaubt in diesem Modell echte Kontrolle.

Aber es gibt auch in der Cloud Kompromisse, auf die ich an dieser Stelle verweisen möchte: Cloud-Computing auf dedizierter Hardware. Diese gibt es bei Azure als Azure Dedicated Hosts, bei AWS als EC2 Dedicated Hosts und bei GCP über Sole-Tenant Nodes. Bei anderen Anbietern oder Plattformen hilft es auch bereits, eine virtuelle Maschine mit dediziertem CPU-Kern zu mieten. Damit ist der gleichzeitige Zugriff mehrerer Kunden auf die Register ausgeschlossen.

Ich hoffe der Artikel hilft sowohl beim Verständnis dieser Kategorie von Security-Bugs, als auch bei der Lösungsfindung. Gerade im Bereich Security und Compliance ist es wertvoll, Alternativen bereit zu halten, um die Vertraulichkeit von sensibleren Daten gewährleisten zu können!

Für weitere Fragen und Beratung stehe ich Ihnen natürlich jederzeit zur Verfügung: mindful-security.eu/kontakt.html. Ich freue mich über Austausch!

Referenzen