it-swarm.com.de

Was ist eine Retpoline und wie funktioniert sie?

Um die Offenlegung des Kernels oder des prozessübergreifenden Speichers (der Spectre -Angriff) abzuschwächen , muss der Linux-Kernel1 wird mit einer neuen Option kompiliert , -mindirect-branch=thunk-extern die in gcc eingeführt wurde, um indirekte Aufrufe über ein sogenanntes retpoline auszuführen.

Dies scheint ein neu erfundener Begriff zu sein, da eine Google-Suche nur in sehr kurzer Zeit verwendet wird (im Allgemeinen alle im Jahr 2018).

Was ist eine Retpoline und wie verhindert sie die jüngsten Angriffe auf die Offenlegung von Kernelinformationen?


1 Es ist jedoch nicht Linux-spezifisch - ein ähnliches oder identisches Konstrukt scheint als Teil der Minderungsstrategien auf anderen Betriebssystemen verwendet zu werden.

229
BeeOnRope

Der Artikel erwähnt von sgbj in den Kommentaren von Googles Paul Turner erklärt das Folgende ausführlicher, aber ich werde es versuchen:

Soweit ich dies aus den derzeit begrenzten Informationen zusammensetzen kann, ist ein Retpoline ein Rückholtrampolin , das eine Endlosschleife verwendet, die niemals ausgeführt wird verhindern Sie, dass die CPU auf das Ziel eines indirekten Sprungs spekuliert.

Der grundlegende Ansatz ist in Andi Kleens Kernel-Zweig zu sehen.

Es wird der neue Aufruf __x86.indirect_thunk eingeführt, der das Aufrufziel lädt, dessen Speicheradresse (die ich ADDR nennen werde) oben auf dem Stapel gespeichert ist, und den Sprung mit a ausführt die RET Anweisung. Der Thunk selbst wird dann mit dem Makro NOSPEC_JMP/CALL aufgerufen, mit dem viele (wenn nicht alle) indirekte Aufrufe und Sprünge ersetzt wurden. Das Makro platziert einfach das Aufrufziel auf dem Stapel und stellt die Rücksprungadresse bei Bedarf korrekt ein (beachten Sie den nichtlinearen Steuerungsfluss):

_.macro NOSPEC_CALL target
    jmp     1221f            /* jumps to the end of the macro */
1222:
    Push    \target          /* pushes ADDR to the stack */
    jmp __x86.indirect_thunk /* executes the indirect jump */
1221:
    call    1222b            /* pushes the return address to the stack */
.endm
_

Die Platzierung von call am Ende ist erforderlich, damit der Kontrollfluss nach Beendigung des indirekten Aufrufs hinter der Verwendung des Makros _NOSPEC_CALL_ zurückbleibt und anstelle eines regulären call

Der Thunk selbst sieht wie folgt aus:

_    call retpoline_call_target
2:
    lfence /* stop speculation */
    jmp 2b
retpoline_call_target:
    lea 8(%rsp), %rsp 
    ret
_

Der Kontrollfluss kann hier etwas verwirrend sein. Lassen Sie mich Folgendes klarstellen:

  • call schiebt den aktuellen Anweisungszeiger (Label 2) auf den Stapel.
  • lea fügt dem Stapelzeiger eine 8 hinzu und verwirft effektiv das zuletzt geschobene Quadword, das die letzte Rücksprungadresse ist (zu Label 2). Danach zeigt die Oberseite des Stapels wieder auf die reale Rücksprungadresse ADDR.
  • ret springt zu _*ADDR_ und setzt den Stapelzeiger auf den Anfang des Aufrufstapels zurück.

Am Ende ist dieses ganze Verhalten praktisch gleichbedeutend mit einem direkten Sprung zu _*ADDR_. Der einzige Vorteil besteht darin, dass der für Rückgabeanweisungen (Return Stack Buffer, RSB) verwendete Verzweigungsprädiktor beim Ausführen der Anweisung call davon ausgeht, dass die entsprechende Anweisung ret zum Label 2 springt.

Der Teil nach dem Label 2 wird eigentlich nie ausgeführt, es ist einfach eine Endlosschleife, die theoretisch die Anweisungspipeline mit JMP Anweisungen füllen würde. Wenn LFENCE, PAUSE oder allgemeiner ein Befehl verwendet wird, der bewirkt, dass die Anweisungspipeline blockiert, wird die CPU daran gehindert, bei dieser spekulativen Ausführung Energie und Zeit zu verschwenden. Dies liegt daran, dass in dem Fall, dass der Aufruf von retpoline_call_target normal zurückkehren würde, LFENCE der nächste auszuführende Befehl wäre. Dies ist auch das, was der Verzweigungsprädiktor basierend auf der ursprünglichen Absenderadresse (dem Label 2) vorhersagt.

So zitieren Sie aus dem Architekturhandbuch von Intel:

Anweisungen, die einem LFENCE folgen, können vor dem LFENCE aus dem Speicher abgerufen werden, werden jedoch erst ausgeführt, wenn der LFENCE abgeschlossen ist.

Beachten Sie jedoch, dass in der Spezifikation niemals erwähnt wird, dass LFENCE und PAUSE dazu führen, dass die Pipeline blockiert. Daher lese ich hier ein bisschen zwischen den Zeilen.

Zurück zu Ihrer ursprünglichen Frage: Die Offenlegung von Kernel-Speicherinformationen ist aufgrund der Kombination von zwei Ideen möglich:

  • Auch wenn die spekulative Ausführung frei von Nebenwirkungen sein sollte, wenn die Spekulation falsch war, wirkt sich die spekulative Ausführung dennoch auf die Cache-Hierarchie aus . Dies bedeutet, dass bei einer spekulativen Ausführung eines Speicherladevorgangs möglicherweise noch eine Cachezeile entfernt wurde. Diese Änderung in der Cache-Hierarchie kann durch sorgfältiges Messen der Zugriffszeit auf den Speicher, der auf den gleichen Cache-Satz abgebildet ist, identifiziert werden.
    Sie können sogar einige Bits des beliebigen Speichers verlieren, wenn die Quelladresse des gelesenen Speichers selbst aus dem Kernel-Speicher gelesen wurde.

  • Der Prädiktor für indirekte Verzweigungen von Intel-CPUs verwendet nur die untersten 12 Bits des Quellbefehls, so dass es einfach ist, alle 2 ^ 12 möglichen Vorhersageverläufe mit benutzergesteuerten Speicheradressen zu vergiften. Diese können dann, wenn der indirekte Sprung innerhalb des Kernels vorhergesagt wird, spekulativ mit Kernelprivilegien ausgeführt werden. Mit dem Cache-Timing-Seitenkanal können Sie somit beliebigen Kernel-Speicher verlieren.

UPDATE: Auf der Kernel-Mailing-Liste gibt es eine laufende Diskussion, die mich zu der Annahme veranlasst, dass Retpolines die Probleme mit der Verzweigungsvorhersage nicht vollständig abmildern, wie dies beim Rückgabestapel der Fall ist Der Puffer (RSB) ist leer, neuere Intel-Architekturen (Skylake +) greifen auf den anfälligen Branch Target Buffer (BTB) zurück:

Retpoline als Schadensbegrenzungsstrategie tauscht indirekte Zweige gegen Renditen aus, um die Verwendung von Vorhersagen zu vermeiden, die vom BTB stammen, da sie von einem Angreifer vergiftet werden können. Das Problem bei Skylake + ist, dass ein RSB-Unterlauf auf die Verwendung einer BTB-Vorhersage zurückgreift, die es dem Angreifer ermöglicht, die Kontrolle über Spekulationen zu übernehmen.

151
Tobias Ribizel

Ein retpoline soll vor dem Ausnutzen der Branch Target Injection ( CVE-2017-5715 ) schützen. Dies ist ein Angriff, bei dem eine indirekte Verzweigungsanweisung im Kernel verwendet wird, um die spekulative Ausführung eines beliebigen Codeblocks zu erzwingen. Der gewählte Code ist ein "Gadget", das dem Angreifer irgendwie nützlich ist. Zum Beispiel kann Code so gewählt werden, dass Kerneldaten durch die Auswirkungen auf den Cache verloren gehen. Die Retpoline verhindert diesen Exploit, indem einfach alle indirekten Verzweigungsbefehle durch einen Rückgabebefehl ersetzt werden.

Ich denke, der Schlüssel an der Retpoline ist nur der "Ret" -Teil, der den indirekten Zweig durch einen Return-Befehl ersetzt, sodass die CPU den Return-Stack-Prädiktor anstelle des ausnutzbaren Branch-Prädiktors verwendet. Wenn stattdessen ein einfacher Push- und ein Return-Befehl verwendet würden, wäre der Code, der spekulativ ausgeführt würde, der Code, zu dem die Funktion irgendwann zurückkehren würde, kein für den Angreifer nützliches Gadget. Der Hauptvorteil des Trampolin-Teils scheint darin zu bestehen, den Rückgabestapel beizubehalten. Wenn die Funktion also tatsächlich zu ihrem Aufrufer zurückkehrt, wird dies korrekt vorhergesagt.

Die Grundidee hinter der Zweigzielinjektion ist einfach. Es nutzt die Tatsache aus, dass die CPU nicht die vollständige Adresse der Quelle und des Ziels von Zweigen in ihren Zweigzielpuffern aufzeichnet. Der Angreifer kann den Puffer also mit Sprüngen in seinem eigenen Adressraum füllen, die zu Vorhersage-Treffern führen, wenn ein bestimmter indirekter Sprung in den Kernel-Adressraum ausgeführt wird.

Beachten Sie, dass Retpoline die Offenlegung von Kernelinformationen nicht direkt verhindert, sondern nur die Verwendung indirekter Verzweigungsbefehle zur spekulativen Ausführung eines Gadgets, das Informationen offenlegt, verhindert. Wenn der Angreifer andere Mittel findet, um das Gadget spekulativ auszuführen, verhindert die Retpoline den Angriff nicht.

Die Abhandlung Spectre Attacks: Exploiting Speculative Execution von Paul Kocher, Daniel Genkin, Daniel Gruss, Werner Haas, Mike Hamburg, Stefan Mangard, Michael Schwarz und Yuval Yarom gibt folgenden Überblick wie indirekte Zweige genutzt werden können:

Ausnutzen von indirekten Zweigen. In dieser Methode wählt der Angreifer ein Gadget aus dem Adressraum des Opfers und veranlasst das Opfer, das Gadget spekulativ auszuführen. Im Gegensatz zu ROP verlässt sich der Angreifer nicht auf eine Sicherheitslücke im Code des Opfers. Stattdessen trainiert der Angreifer den Verzweigungszielpuffer (Branch Target Buffer, BTB), um eine Verzweigung von einem indirekten Verzweigungsbefehl zu der Adresse des Gadgets falsch vorherzusagen, was zu einer spekulativen Ausführung des Gadgets führt. Während die spekulativ ausgeführten Anweisungen verworfen werden, werden ihre Auswirkungen auf den Cache nicht rückgängig gemacht. Diese Effekte können vom Gadget verwendet werden, um vertrauliche Informationen zu verlieren. Wir zeigen, wie mit dieser Methode bei sorgfältiger Auswahl eines Gadgets ein beliebiges Gedächtnis des Opfers ausgelesen werden kann.

Um den BTB zu missbrauchen, findet der Angreifer die virtuelle Adresse des Gadgets im Adressraum des Opfers und führt dann indirekte Verzweigungen zu dieser Adresse durch. Diese Schulung wird über den Adressraum des Angreifers durchgeführt. Dabei spielt es keine Rolle, was sich unter der Gadget-Adresse im Adressraum des Angreifers befindet. Alles, was erforderlich ist, ist, dass der Zweig, der zum Trainieren von Zweigen verwendet wird, dieselbe virtuelle Zieladresse verwendet. (Solange der Angreifer Ausnahmen behandelt, kann der Angriff auch dann ausgeführt werden, wenn kein Code auf die virtuelle Adresse des Gadgets im Adressraum des Angreifers abgebildet ist.) Außerdem ist keine vollständige Übereinstimmung mit der Quelladresse erforderlich der für die Schulung verwendeten Niederlassung und die Adresse der Zielniederlassung. Somit hat der Angreifer erhebliche Flexibilität beim Einrichten des Trainings.

Ein weiterer Blogeintrag mit dem Titel Lesen von privilegiertem Speicher mit einem Seitenkanal vom Project Zero-Team von Google zeigt, wie die Branch Target Injection verwendet werden kann, um einen funktionierenden Exploit zu erstellen.

45
Ross Ridge

Diese Frage wurde vor einiger Zeit gestellt und verdient eine neuere Antwort.

Executive Summary :

"Retpoline" -Sequenzen sind ein Softwarekonstrukt, mit dem indirekte Verzweigungen von der spekulativen Ausführung isoliert werden können. Dies kann angewendet werden, um sensible Binärdateien (z. B. Betriebssystem- oder Hypervisor-Implementierungen) vor Angriffen durch Branch Target Injection gegen ihre indirekten Zweige zu schützen.

Das Wort " ret poline " ist ein portmantea der Wörter "return" und "trampoline" ", ähnlich wie die Verbesserung" rel poline "aus" Relativruf "und" Trampolin "geprägt wurde. Es ist ein Trampolinkonstrukt, das unter Verwendung von Rückholoperationen konstruiert wurde, was auch bildlich sicherstellt, dass jede damit verbundene spekulative Ausführung endlos "abprallt".

Um die Offenlegung des Kernels oder des prozessübergreifenden Speichers (der Spectre-Angriff) abzuschwächen, muss der Linux-Kernel [1] wird mit der neuen Option -mindirect-branch=thunk-extern kompiliert, die in gcc eingeführt wurde, um indirekte Aufrufe über eine sogenannte Retpoline durchzuführen.

[1] Es ist jedoch nicht Linux-spezifisch - ein ähnliches oder identisches Konstrukt scheint als Teil der Minderungsstrategien auf anderen Betriebssystemen verwendet zu werden.

Die Verwendung dieser Compileroption schützt nur vor Spectre V2 in betroffenen Prozessoren, für die die für CVE-2017- erforderliche Aktualisierung des Mikrocodes erforderlich ist. 5715. Es wird '' auf jedem Code (nicht nur einem Kernel) funktionieren , aber nur Code, der "Geheimnisse" enthält, ist es wert, angegriffen zu werden.

Dies scheint ein neu erfundener Begriff zu sein, da eine Google-Suche nur in sehr kurzer Zeit verwendet wird (im Allgemeinen alle im Jahr 2018).

Der LLVM-Compiler hat seit vor dem 4. Januar 2018 einen -mretpoline -Schalter. An diesem Datum wurde die Sicherheitsanfälligkeit zuerst öffentlich gemeldet . GCC hat die Patches zur Verfügung gestellt ​​7. Januar 2018.

Das CVE-Datum deutet darauf hin, dass die Sicherheitsanfälligkeit 2017 entdeckt wurde , aber einige der in den letzten zwei Jahrzehnten hergestellten Prozessoren betrifft (daher wurde sie wahrscheinlich schon vor langer Zeit entdeckt).

Was ist eine Retpoline und wie verhindert sie die jüngsten Angriffe auf die Offenlegung von Kernelinformationen?

Zunächst einige Definitionen:

  • Trampolin - Manchmal bezeichnet man Trampoline als indirekte Sprungvektoren als Speicherorte, an denen Adressen gespeichert sind, die auf Interrupt-Serviceroutinen, E/A-Routinen usw. verweisen der Begriff Trampolin. GCC hat traditionell verschachtelte Funktionen unterstützt, indem ein ausführbares Trampolin zur Laufzeit erstellt wird, wenn die Adresse einer verschachtelten Funktion verwendet wird. Dies ist ein kleines Stück Code, das sich normalerweise auf dem Stapel im Stapelrahmen der enthaltenden Funktion befindet. Das Trampolin lädt das statische Kettenregister und springt dann zur realen Adresse der verschachtelten Funktion.

  • Thunk - Ein Thunk ist ein Unterprogramm, mit dem eine zusätzliche Berechnung in ein anderes Unterprogramm eingefügt wird. Thunks werden hauptsächlich verwendet, um eine Berechnung zu verzögern, bis das Ergebnis benötigt wird, oder um Operationen am Anfang oder Ende der anderen Unterroutine einzufügen

  • Memoization - Eine gespeicherte Funktion "merkt" sich die Ergebnisse, die bestimmten Eingaben entsprechen. Nachfolgende Aufrufe mit gespeicherten Eingaben geben das gespeicherte Ergebnis zurück, anstatt es neu zu berechnen, wodurch die Hauptkosten eines Aufrufs mit bestimmten Parametern von allen außer dem ersten Aufruf der Funktion mit diesen Parametern eliminiert werden.

Grob gesagt ist ein Retpolin ein Trampolin mit einem return als thunk , to ' verderben ' Merken im indirekten Zweig Prädiktor.

Source : Die Retpoline enthält einen PAUSE-Befehl für Intel, für AMD ist jedoch ein LFENCE-Befehl erforderlich, da der PAUSE-Befehl auf diesem Prozessor kein Serialisierungsbefehl ist Es wird darüber spekuliert, dass auf die Rückkehr gewartet wird, um das richtige Ziel falsch vorherzusagen.

Arstechnica hat eine einfache Erklärung des Problems:

Jeder Prozessor hat ein Architekturverhalten (das dokumentierte Verhalten, das beschreibt, wie die Anweisungen funktionieren und von dem Programmierer abhängig sind, um ihre Programme zu schreiben) und ein Mikroarchitekturverhalten (die Art und Weise, wie sich eine tatsächliche Implementierung der Architektur verhält). Diese können auf subtile Weise voneinander abweichen. In der Architektur beispielsweise wartet ein Programm, das einen Wert von einer bestimmten Adresse im Speicher lädt, bis die Adresse bekannt ist, bevor es versucht, den Ladevorgang durchzuführen. In der Mikroarchitektur versucht der Prozessor jedoch möglicherweise, die Adresse spekulativ zu erraten, damit sie gestartet werden kann Laden des Wertes aus dem Speicher (der langsam ist), noch bevor absolut sicher ist, welche Adresse er verwenden soll.

Wenn der Prozessor falsch vermutet, ignoriert er den erratenen Wert und führt das Laden erneut durch, diesmal mit der richtigen Adresse. Das architektonisch definierte Verhalten bleibt somit erhalten. Diese fehlerhafte Vermutung stört jedoch andere Teile des Prozessors, insbesondere den Inhalt des Caches. Diese mikroarchitektonischen Störungen können erkannt und gemessen werden, indem man festlegt, wie lange es dauert, auf Daten zuzugreifen, die sich im Cache befinden sollen (oder nicht), damit ein böswilliges Programm Rückschlüsse auf die im Speicher abgelegten Werte ziehen kann. ".

Aus Intels Artikel: " Retpoline: A Branch Target Injection Mitigation " ( . PDF ):

Eine Retpoline-Sequenz verhindert, dass die spekulative Ausführung des Prozessors den "indirekten Verzweigungsprädiktor" (eine Möglichkeit zur Vorhersage des Programmflusses) verwendet, um an eine Adresse zu spekulieren, die von einem Exploit gesteuert wird (Erfüllung von Element 4 der fünf Elemente der Verzweigungszielinjektion (Specter-Variante 2) ) die oben aufgeführte Zusammensetzung ausnutzen. ".

Beachten Sie, dass Element 4 lautet: "Der Exploit muss diesen indirekten Zweig erfolgreich beeinflussen, um ein Gadget spekulativ falsch vorherzusagen und auszuführen. Dieses Gadget, das vom Exploit ausgewählt wird, leitet die geheimen Daten über einen Seitenkanal weiter, normalerweise durch Cache-Timing.".

7
Rob