Reptar: FSRM/REX-Schwachstelle in Intel-CPUs
(lock.cmpxchg8b.com)- Bei einigen Intel-Prozessoren kann die Kombination aus
rep movsund einem redundantenrex.r-Präfix im Zusammenspiel mit der FSRM-Optimierung dazu führen, dass die CPU in einen „Glitch“-Zustand außerhalb der normalen Regeln gerät - Ursache ist das lockere Präfix-Decoding von x86 sowie der Umstand, dass ein eigentlich bedeutungsloses
rex-Präfix bei Befehlen mit impliziten Operanden wiemovsbeinen bestimmten Optimierungspfad nimmt - Googles Verifikations-Pipeline entdeckte im August 2023 bei dieser Kombination unvorhersehbare Ergebnisse und beobachtete unerwartete Sprünge, ignorierte unbedingte Sprünge sowie Anomalien bei der Aufzeichnung des Instruction Pointers durch
xsaveundcall - Wenn mehrere Kerne denselben Bug gleichzeitig auslösen, kann es zu einer Machine Check Exception und einem Systemstillstand kommen; da dies auch in einer unprivilegierten Gast-VM reproduzierbar ist, ist es für Cloud-Umgebungen relevant
- Intel hat Microcode-Updates für betroffene Prozessoren veröffentlicht; falls ein Update nicht möglich ist, können fast strings über
IA32_MISC_ENABLEdeaktiviert werden, was jedoch erhebliche Performance-Einbußen mit sich bringt
x86-Präfixe und rep movsb
rep movsbist eine idiomatische Methode in x86, um Speicher zu verschieben: Wenn Quelle, Ziel, Richtung und Zähler gesetzt sind, übernimmt der Prozessor die wiederholte Kopie- Der eigentliche Befehl ist
movsb;repist ein Präfix (prefix), das den Befehl so verändert, dass er mehrfach wiederholt wird - Das x86-Befehls-Decoding ist vergleichsweise locker, sodass bedeutungslose oder kollidierende Präfixe in der Regel ignoriert werden
- Compiler können solche redundanten Präfixe nutzen, um einen einzelnen Befehl bis zu einer gewünschten Alignment-Grenze zu paddden
rex,vexundevexsind Präfixe, die die Decoding-Art des folgenden Befehls verändern
Die problematische Kombination mit dem rex-Präfix
- i386 hatte 8 General-Purpose-Register, sodass Register mit 3 Bit adressiert werden konnten; x86-64 hat jedoch 16 General-Purpose-Register und benötigt daher zusätzliche Bits
- Das
rex-Präfix stellt zusätzliche Bits bereit, die der nächste Befehl beim Codieren von Operanden mitverwenden kann- Es wird üblicherweise als
rex.rxbnotiert, wobei die Bitsb,x,rundwoptional gesetzt werden
- Es wird üblicherweise als
- Bei
movsbwerden die Operanden nicht explizit im Befehl angegeben, sondern sind alle implizit; daher sollten dierex-Bits inrex.rxb rep movsbkeine Bedeutung haben - Normalerweise ignoriert der Prozessor ein solches
rex-Präfix stillschweigend, auf Systemen mit Unterstützung für fast short repeat move führt diese Kombination jedoch zu einer Schwachstelle
FSRM und betroffene Prozessoren
- FSRM ist eine mit Ice Lake eingeführte Funktion, die die Grenzen von ERMS bei kurzen Strings ausgleicht
- ERMS (enhanced repeat move/store) kann bestehenden
rep movsb-Code beschleunigen, indem Buffer-Alignment und breite Stores im Microcode behandelt werden- Die anfänglichen Setup-Kosten sind hoch, weshalb es für sehr kurze Strings ungeeignet ist
- FSRM ist dafür gedacht, kurze Verschiebungen von 128 Byte oder weniger schneller zu verarbeiten
- Ob Unterstützung vorhanden ist, lässt sich in
/proc/cpuinfoin der Zeileflagsam Flagfsrmerkennen - Beispiele für Prozessoren mit FSRM sind:
- Ice Lake
- Rocket Lake
- Tiger Lake
- Raptor Lake
- Alder Lake
- Sapphire Rapids
- Diese Liste ist nicht vollständig; für die vollständige Liste sollte das Intel-Advisory INTEL-SA-00950 konsultiert werden
Entdeckung und Reproduktion
- Googles Verifikations-Pipeline führt mit der Technik Oracle Serialization zwei Formen zufällig erzeugter Programme aus und vergleicht anschließend, ob der Endzustand identisch ist
- Eine zugehörige Erklärung findet sich im früheren Artikel Oracle Serialization
- Im August 2023 traten unvorhersehbare Ergebnisse auf, als einem FSRM-optimierten
rep movsein redundantesrex.r-Präfix hinzugefügt wurde - Beobachtete Anomalien waren:
- Sprünge an unerwartete Positionen
- Ignorieren unbedingter Sprünge
- Der Instruction Pointer wurde bei
xsave- odercall-Befehlen nicht korrekt aufgezeichnet - Debugger meldeten unmögliche Zustände
- Wenn mehrere Kerne denselben Bug auslösen, kann der Prozessor eine Machine Check Exception melden und stehen bleiben
- Da dies auch innerhalb einer unprivilegierten Gast-VM reproduzierbar ist, ist es für Cloud-Anbieter ein sicherheitsrelevantes Problem
- Reproduktions-Tools und Forschungsmaterialien wurden in Googles security research repository veröffentlicht
- Ein lokaler Mirror des Tools
icebreakist ebenfalls als icebreak.tar.gz verfügbar
- Ein lokaler Mirror des Tools
icebreakversucht die Reproduktion mit angegebenen Paaren unterschiedlicher Kerne- Auf nicht betroffenen Systemen sollte es wie eine Endlosschleife wirken und keine Ausgabe erzeugen
- Auf betroffenen Systemen wird bei jeder erfolgreichen Reproduktion ein
.ausgegeben - Auf SMT-Geschwisterkernen können zufällige Sprünge beobachtet werden
- Auf SMP-Geschwisterkernen desselben Packages können Machine Checks beobachtet werden
- Wenn nicht zwei unterschiedliche Kerne angegeben werden, kann ein Hammer-Thread erforderlich sein
Mögliche Ursache und beobachtete Auswirkungen
- Da das Microcode-Verhalten moderner Systeme nicht öffentlich ist, kann die eigentliche Ursache nur als theoriegestützte Beobachtung behandelt werden
- Eine CPU ist grob in Frontend und Backend unterteilt
- Das Frontend holt und decodiert Befehle und erzeugt μops
- Das Backend führt Befehle out-of-order aus, speichert Ergebnisse im ROB (Reorder Buffer) und räumt sie auf
- Dieser Bug scheint dazu zu führen, dass das Frontend die Größe des
movsb-Befehls falsch berechnet und dadurch ein Zustand entsteht, in dem spätere ROB-Einträge mit falschen Adressen verknüpft werden - In diesem Zustand entsteht ein verwirrter Zustand, in dem der Instruction Pointer falsch berechnet wird
- Das System kann sich letztlich intern wieder in einen konsistenten Zustand erholen, Zwischenergebnisse können jedoch falsch sein
- Wenn mehrere SMT- oder SMP-Kerne gleichzeitig in diesen Zustand geraten, kann genügend mikroarchitektonischer Zustand beschädigt werden, um einen Machine Check zu erzwingen
- Der Systemzustand kann so stark beschädigt werden, dass ein Machine Check ausgelöst wird, und bei Prozessen, die auf SMT-Geschwisterkernen eingeplant sind, wurde Interferenz zwischen Threads beobachtet
- Ob sich die Beschädigung präzise genug für eine Privilegieneskalation steuern lässt, ist nicht bestätigt
Gegenmaßnahmen
- Intel hat aktualisierten Microcode für alle betroffenen Prozessoren unter INTEL-SA-00950 veröffentlicht
- Betriebssystem- oder BIOS-Anbieter stellen möglicherweise bereits Updates bereit
- Falls kein Update möglich ist, können fast strings über das modellspezifische Register
IA32_MISC_ENABLEdeaktiviert werden - Das Deaktivieren von fast strings verursacht erhebliche Performance-Einbußen und sollte nur verwendet werden, wenn es unbedingt notwendig ist
Materialien zu verwandten CPU-Bugs
- Google veröffentlicht gefundene CPU-Bugs; einige davon sind auch dann lesenswert, wenn sie keine Sicherheitsauswirkungen haben
- Beispielmaterialien:
- movlps just doesn’t work: ein Fall, in dem
movlpsnicht funktioniert - registers can sometimes roll back: ein Fall, in dem Register auf frühere Werte zurückrollen können
- movlps just doesn’t work: ein Fall, in dem
1 Kommentare
Hacker-News-Kommentare
Verwandter Artikel: https://cloud.google.com/blog/products/identity-security/goo...
stammt von https://news.ycombinator.com/item?id=38268043, aber die Kommentare wurden hier zusammengeführt
Beim Lesen dieses Artikels wurde mir klar, wie wenig ich über die Hardware weiß, auf der meine Software läuft
Dort heißt es: „Präfixe können das Verhalten von Instruktionen verändern, indem sie Funktionen ein- oder ausschalten“ – da frage ich mich, warum man zum Ein- und Ausschalten von Funktionen überhaupt ein „Präfix“ braucht
Ist das dazu da, Funktionen dynamisch umzuschalten, ohne ins BIOS zu gehen?
Das REP-Präfix ist am gebräuchlichsten; es sorgt dafür, dass dieselbe Instruktion eine variable Anzahl von Malen wiederholt wird
Die Wiederholungsanzahl wird aus dem CX-Register genommen und macht häufige Schleifen wie das Verschieben von Objekten im Speicher sehr kurz
Eine memcpy-Funktion wird oft als eine einzige
REP MOVS-Instruktion inline eingefügt, gegebenenfalls mit einer zusätzlichen Instruktion, die den Zähler nach CX kopiertDas REX-Präfix ist ebenfalls recht häufig, weil 64-Bit-Programme oft mit 64-Bit-Werten und -Adressen arbeiten
Kein Präfix schaltet global konfigurierbare Dinge wie im BIOS um; alle geben nur an, was die nächste Instruktion tun soll
Selten verwendete Adressierungsarten bekommen ein „Segmentpräfix“, damit statt DS ein anderes Segment verwendet wird, und das „REX“-Präfix in x86_64 fügt den Registerfeldern Bits hinzu, sodass 16 allgemeine Register nutzbar sind
Ebenso macht das „LOCK“-Präfix bestimmte Speicheroperationen gegenüber dem Rest des Systems atomar, auch wenn die ursprüngliche Spezifikation etwas schwach war; mit
LOCK CMPXCHGlässt sich etwa Compare-and-Set umsetzenAndere CPU-Architekturen drücken solche Operationen ebenfalls aus, packen sie aber meist in den bestehenden Instruktionsraum, wodurch mehr Bits nötig werden, um alle Instruktionen darzustellen
Das hier betroffene „REP“-Präfix ist besonders eine Ausnahme: ein uraltes, per Mikrokode implementiertes Wiederholungspräfix
Trotzdem steht es für auch heute noch performancekritische Operationen wie
memset/memmove, weshalb CPU-Hersteller es weiter optimieren – und dieser Bug scheint dabei entstanden zu seinDas größte Problem ist, dass der Instruktionskodierungsraum „effizient genutzt“ wurde
Als später neue Instruktionen und, schlimmer noch, zusätzliche Register hinzukamen, musste man irgendwie neue Instruktionsvarianten unterbringen, und das geschah durch das Anhängen von Präfixen
Jedes Mal, wenn der Instruktionssatz erweitert wurde, hat man einen Teil des Opcode-Raums herausgeschnitten und ein neues Präfix hineingestopft
Dass Intel dieses Jahr erneut eine weitere neue Methode vorgeschlagen hat, deutet darauf hin, dass sich dieser Trend fortsetzen wird
Beim Diagnoseprozess musste ich an qemu denken, wenn es auf repz ret trifft: https://repzret.org/p/repzret/
Ich finde, solche Titel sollten nach den HN-Regeln verboten sein
Sie sagen überhaupt nicht, worum es in dem Link geht, und die URL macht es eher noch verwirrender
Bei so einem nichtssagenden Titel sollte der Einreicher meiner Meinung nach eine kurze Erklärung hinzufügen
Wir haben schon gesehen, dass Leute den Link nicht anklicken, wenn zu viel Kontext im Titel steht, und dann nur noch in den Kommentaren an ihren eigenen Interessen feilen, als würden sie auf einen Tweet reagieren
HN wählt einen Mittelweg zwischen intellektueller Neugier und dem Anreiz, den Link anzuklicken
Selbst wenn jemand einen vagen Titel ablehnt und den Link nicht öffnet, antwortet er dann wenigstens auf Leute, die den Link angeklickt haben; das ist immer noch besser als anderswo im Internet
Beiträge, die nicht genug Substanz haben, um einen vagen und pfiffigen Titel zu rechtfertigen, fallen – anders als dieser hier – von der Startseite
Der Artikel ist wirklich sehr gut geschrieben
Ich kenne mich weder mit Assemblerprogrammierung noch mit dem Intel-Instruktionssatz und auch kaum mit Mikroarchitektur aus, konnte der Erklärung aber folgen und habe das Gefühl, grob verstanden zu haben, was hier passiert
Mich würde interessieren, ob jemand weiß, ob auch AMD-CPUs betroffen sind
Wenn das Problem wirklich darin besteht, dass der Prozessor bei der Instruktionslänge durcheinanderkommt, ist es beeindruckend, dass sich das per Mikrokode ohne großen Performanceverlust beheben lässt
Mein Bauchgefühl kann völlig falsch liegen, aber ich hätte erwartet, dass die Berechnung der Instruktionslänge direkt in Logikgattern synthetisiert wird
Beim zweiten Nachdenken könnte es aber sein, dass der uOP-Decoder in Hardware völlig in Ordnung ist und eine per Mikrokode optimierte Kopierroutine versucht, etwas über den uOP-Stream zu folgern, das gar nicht stimmt
Zum Beispiel so etwas wie: „Ah, das ist ein
rep mov, also gehe ich für die Schleife einfach zwei uOPs zurück“Das Intel-CPU-Team wird dazu wohl kaum Details veröffentlichen
Ich kenne mich mit „ERMS“ und „FSRM“ nicht gut aus, und selbst bei Google scheint es kaum brauchbares Material dazu zu geben.
Ich frage mich, ob das nur CPUID-Flags sind, die anzeigen, dass
rep movsbmit maximaler Leistung statt einer optimierten SSE-memcpy-Implementierung verwendet werden kann, oder ob es sich um eine besondere Kodierung oder ein Präfix handelt, dasrep movsbschneller macht.Falls Letzteres zutrifft, ist mir nicht klar, warum das nötig ist und wie
fsrmgenutzt wird.ERMS war offenbar eine günstigere Alternative zu AVX, und FSRM scheint die bessere Variante für kurze Blöcke gewesen zu sein.
„In späteren Low-Cost-Versionen der Prozessoren, den 2017 erschienenen Kaby Lake Celeron und Pentium, fehlt AVX für schnelle Speicherkopien, aber Enhanced REP MOVSB ist vorhanden.
Und einige seit 2018 erschienene Intel-Mobil- und Low-Power-Architekturen basierten nicht auf SkyLake, kopierten mit REP MOVSB aber pro CPU-Zyklus ungefähr doppelt so viele Bytes wie Mikroarchitekturen der vorherigen Generation.“
„Vor Fast Short REP MOV (FSRM) in der Ice-Lake-Mikroarchitektur war Enhanced REP MOVSB (ERMSB) nur dann schneller als AVX-Kopien oder Kopien mit allgemeinen Registern, wenn die Blockgröße mindestens 256 Byte betrug.
Bei Blöcken unter 64 Byte war die interne Startkosten von ERMSB mit etwa 35 Zyklen hoch, daher war es deutlich langsamer, und die FSRM-Funktion sollte auch Blöcke unter 128 Byte beschleunigen.“
[1] https://stackoverflow.com/a/43837564
[2] http://www.intel.com/content/dam/www/public/us/en/documents/...
Die Auswahl optimaler Befehle und deren Scheduling kann zur Compile-Zeit statisch erfolgen oder zur Laufzeit dynamisch, etwa durch die Wahl einer von mehreren Bibliotheksfunktionen oder per JIT.
Um zur Laufzeit zu erkennen, welches Befehlsscheduling optimal ist, muss man die tatsächliche CPU kennen.
Man könnte Tabellen für alle CPU-Modelle vorhalten, oder das Betriebssystem fragen, ob die laufende CPU diese Optimierung implementiert.
Linux brauchte dafür einen Patch, damit gemeldet werden kann, dass die CPU diese Optimierung implementiert.
https://www.phoronix.com/news/Intel-5.6-FSRM-Memmove
rep movsbschnell ist und deshalb keine SSE/AVX-optimierte Implementierung verwendet werden muss.Ich habe gesehen, dass im Intel-Hinweis [1] Folgendes steht:
Intel dankte den Intel-Mitarbeitern, die dieses Problem intern entdeckt haben, und ebenso den Google-Mitarbeitern, die es gemeldet haben.
[1] https://www.intel.com/content/www/us/en/security-center/advi...
Ebenfalls sehenswert ist der Intel-Hinweis mit der Beschreibung der Auswirkungen: https://www.intel.com/content/www/us/en/security-center/advi...
„Auf manchen Intel(R)-Prozessoren kann eine Prozessor-Befehlssequenz unerwartetes Verhalten auslösen, wodurch ein authentifizierter Benutzer über lokalen Zugriff eine Rechteausweitung, Offenlegung von Informationen oder einen Denial-of-Service ermöglichen kann.“
Konrad Magnusson aus dem Victoria-3-Team von Paradox Interactive hat im Zusammenhang damit und mit mimalloc etwas gefunden: https://github.com/microsoft/mimalloc/issues/807
Ich weiß nicht, ob das vollständig damit zusammenhängt, aber möglich ist es.