2 Punkte von GN⁺ 2023-11-15 | 1 Kommentare | Auf WhatsApp teilen
  • Bei einigen Intel-Prozessoren kann die Kombination aus rep movs und einem redundanten rex.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 wie movsb einen 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 xsave und call
  • 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_ENABLE deaktiviert werden, was jedoch erhebliche Performance-Einbußen mit sich bringt

x86-Präfixe und rep movsb

  • rep movsb ist 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; rep ist 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, vex und evex sind 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.rxb notiert, wobei die Bits b, x, r und w optional gesetzt werden
  • Bei movsb werden die Operanden nicht explizit im Befehl angegeben, sondern sind alle implizit; daher sollten die rex-Bits in rex.rxb rep movsb keine 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/cpuinfo in der Zeile flags am Flag fsrm erkennen
  • 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
  • Im August 2023 traten unvorhersehbare Ergebnisse auf, als einem FSRM-optimierten rep movs ein redundantes rex.r-Präfix hinzugefügt wurde
  • Beobachtete Anomalien waren:
    • Sprünge an unerwartete Positionen
    • Ignorieren unbedingter Sprünge
    • Der Instruction Pointer wurde bei xsave- oder call-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 icebreak ist ebenfalls als icebreak.tar.gz verfügbar
  • icebreak versucht 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_ENABLE deaktiviert 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:

1 Kommentare

 
GN⁺ 2023-11-15
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?

    • Lies einfach https://wiki.osdev.org/X86-64_Instruction_Encoding#Legacy_Pr...
      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 kopiert
      Das 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
    • In diesem Fall dient ein „Präfix“ meist dazu, den Instruktionskodierungsraum zu erweitern
      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 CMPXCHG lässt sich etwa Compare-and-Set umsetzen
      Andere 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 sein
    • Ein Präfix ist ein Modifikator für eine bestimmte Instruktion, die der Prozessor ausführt, etwa um die Operandenbreite zu steuern oder für Parallelität eine Sperre zu aktivieren
    • x86 wurde 1978 praktisch für den Betrieb primitiver Laserdrucker oder ähnlicher Aufgaben entworfen
      Das 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
    • x86 wurde als Instruktionssatzarchitektur über mehr als 40 Jahre hinweg immer weiter angebaut, und weil es Instruktionen variabler Länge verwendet, sieht es heute so aus
      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

    • Stimme ich nicht zu
      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 movsb mit maximaler Leistung statt einer optimierten SSE-memcpy-Implementierung verwendet werden kann, oder ob es sich um eine besondere Kodierung oder ein Präfix handelt, das rep movsb schneller macht.
    Falls Letzteres zutrifft, ist mir nicht klar, warum das nötig ist und wie fsrm genutzt wird.

    • Ich habe dieses Material gefunden [1], dort ist auch das Intel-Optimierungshandbuch [2] verlinkt.
      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/...
    • FSRM ist nur der Name einer CPU-Optimierung, die bestehenden Code beeinflusst.
      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
    • Das Flag zeigt nur an, dass auf dieser CPU rep movsb schnell 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...

    • Ich frage mich, wie viel früher die Intel-Mitarbeiter das Problem entdeckt haben als Google.
  • 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.“

    • Dieses „manchen“ scheint fast alle Intel-x86-CPUs zu meinen, die in den letzten sechs Jahren hergestellt wurden.
  • 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.

    • Falls nicht irgendwie unnötige Präfixe ausgegeben wurden, scheint ein Zusammenhang eher unwahrscheinlich.