Prozessoroptimierung entfernt oder ändert sicherheitskritischen Code
Beschreibung
Prozessoroptimierung entfernt oder ändert sicherheitskritischen Code tritt auf, wenn Entwickler sicherheitskritische Schutzmechanismen implementieren, die anschließend durch Prozessoroptimierungen entfernt, geändert oder umgangen werden. Moderne Prozessoren verwenden verschiedene Optimierungstechniken wie spekulative Ausführung, Out-of-Order-Ausführung, Sprungvorhersage und Cache-Optimierung. Diese Optimierungen können Sicherheitsmaßnahmen untergraben, indem sie Codepfade ausführen, die eingeschränkt sein sollten, sensible Daten durch Seitenkanale preisgeben oder Sicherheitsprüfungen eliminieren, die aus rein funktionaler Perspektive unnötig erscheinen.
Risiko
Diese Schwachstellenklasse ist für einige der schwerwiegendsten Hardware-Sicherheitsprobleme verantwortlich, die in den letzten Jahren entdeckt wurden. Spectre- und Meltdown-Schwachstellen demonstrierten, dass spekulative Ausführung sensiblen Kernel-Speicher an nicht privilegierte Prozesse weitergeben kann. Das Risiko ist extrem hoch, weil: (1) diese Schwachstellen grundlegende Prozessorarchitekturen betreffen, die über Milliarden von Geräten verwendet werden, (2) softwarebasierte Mitigationen oft erhebliche Leistungseinbußen verursachen, (3) vollständige Hardware-Fixes möglicherweise neue Prozessordesigns erfordern, und (4) die Schwachstellen prozess- und privilegienebenenübergreifende Datenlecks ermöglichen, die Betriebssystem-Sicherheitsgrenzen untergraben.
Lösung
Implementieren Sie Compiler-Schutzmaßnahmen wie serialisierende Anweisungen (lfence), um spekulative Ausführung zu verhindern, wo nötig. Verwenden Sie Memory Barriers zur Durchsetzung der Ausführungsreihenfolge. Wenden Sie Betriebssystem-Patches an, die Kernel Page Table Isolation (KPTI/KAISER) implementieren. Aktivieren Sie Microcode-Updates, die Sprungvorhersage-Mitigationen bieten. Vermeiden Sie das Speichern sensibler Daten in Speicherbereichen, die für spekulative Ausführung zugänglich sind. Verwenden Sie konstant-zeitliche Algorithmen, die keine Zeitvariationen aufweisen. Erwägen Sie die Verwendung spezialisierter Hardware-Sicherheitsmodule für kryptografische Operationen. Bleiben Sie auf dem neuesten Stand bezüglich Sicherheitshinweisen der Prozessorhersteller und wenden Sie alle empfohlenen Mitigationen an.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Integrität | Bereich: Integrität Schutzmechanismus umgehen - Prozessoroptimierungen können die Ausführungsreihenfolge ändern und Sicherheitsmaßnahmen umgehen, die auf spezifische Ausführungssequenzen angewiesen sind. |
| Vertraulichkeit | Bereich: Vertraulichkeit Anwendungsdaten lesen - Spekulative Ausführung und Cache-Seitenkanale können sensible Daten aus geschützten Speicherbereichen preisgeben. |
| Zugriffskontrolle | Bereich: Zugriffskontrolle Schutzmechanismus umgehen - Privilegiengrenzen zwischen Benutzer- und Kernelmodus können durch transiente Ausführungsangriffe verletzt werden. |
Beispielcode und Lösung
Verwundbarer Code
// Verwundbar: Code anfällig für Spectre Variante 1 (Bounds Check Bypass)
#include <stdint.h>
#define ARRAY_SIZE 16
uint8_t array1[ARRAY_SIZE];
uint8_t array2[256 * 512]; // Probe-Array
// Angreifer-kontrollierte Werte
size_t malicious_x; // Out-of-Bounds-Index
uint8_t verwundbare_funktion(size_t x) {
// Grenzprüfung - scheint vor Out-of-Bounds-Zugriff zu schützen
if (x < ARRAY_SIZE) {
// Verwundbar: Während spekulativer Ausführung wird dieser Code
// ausgeführt, BEVOR die Grenzprüfung verifiziert ist
// Prozessor führt spekulativ mit nicht vertrauenswürdigem x-Wert aus
return array2[array1[x] * 512];
}
return 0;
}
// Angriffsszenario:
// 1. Branch Predictor trainieren, x < ARRAY_SIZE zu erwarten
// 2. Mit malicious_x aufrufen, das auf geheime Daten zeigt
// 3. Spekulative Ausführung liest array1[malicious_x] (geheimes Byte)
// 4. Geheimes Byte als Index in array2 verwendet (Cache-Seiteneffekt)
// 5. array2-Zugriffszeiten messen, um geheimen Wert zu bestimmen
// Verwundbar: Compiler kann sicherheitskritischen Code wegoptimieren
#include <string.h>
void verwundbares_passwort_löschen(char *password, size_t len) {
// Passwort aus Speicher löschen
memset(password, 0, len);
// Verwundbar: Compiler kann dies wegoptimieren!
// Da password nach memset nicht verwendet wird, betrachtet der Compiler
// dies als "toten Speicher" und entfernt es
// Passwort bleibt für potenzielle Extraktion im Speicher
}
// Assembly-Ausgabe könnte den memset-Aufruf komplett entfernen
// weil der Optimierer keinen beobachtbaren Effekt sieht
// Verwundbar: Race Condition durch spekulative Ausführung ermöglicht
// Spectre Variante 2 (Branch Target Injection)
void verwundbarer_indirekter_aufruf(void (*func_ptr)(void)) {
// Verwundbar: Indirekter Branch kann fehlvorhergesagt werden
// Angreifer kann Branch Target Buffer trainieren, um Ausführung umzuleiten
// Prozessor kann spekulativ angreiferkontrollierten Code ausführen
// bevor der tatsächliche Funktionszeiger aufgelöst wird
func_ptr();
}
Sichere Lösung
// Sicher: Spectre Variante 1 Mitigation mit lfence
#include <stdint.h>
#include <x86intrin.h> // Für _mm_lfence
#define ARRAY_SIZE 16
uint8_t array1[ARRAY_SIZE];
uint8_t array2[256 * 512];
uint8_t sichere_funktion(size_t x) {
if (x < ARRAY_SIZE) {
// Sicher: Serialisierende Anweisung einfügen
// lfence verhindert spekulative Ausführung über diesen Punkt hinaus
_mm_lfence();
// Jetzt sicher: Grenzprüfung ist garantiert abgeschlossen
// bevor dieser Speicherzugriff erfolgt
return array2[array1[x] * 512];
}
return 0;
}
// Alternative: Array-Index-Maskierung
uint8_t sichere_funktion_maske(size_t x) {
// Sicher: Index maskieren, um Out-of-Bounds-Zugriff zu verhindern
// Auch während spekulativer Ausführung ist der Zugriff begrenzt
size_t safe_x = x & (ARRAY_SIZE - 1); // Setzt Potenz von 2 voraus
// Zusätzliche Prüfung für Korrektheit
if (x < ARRAY_SIZE) {
return array2[array1[safe_x] * 512];
}
return 0;
}
// Sicher: Sicherstellen, dass Speicherlöschung nicht wegoptimiert wird
#include <string.h>
// Methode 1: volatile verwenden, um Optimierung zu verhindern
void sicheres_passwort_löschen_volatile(char *password, size_t len) {
volatile char *p = (volatile char *)password;
while (len--) {
*p++ = 0;
}
}
// Methode 2: Compilerspezifisches sicheres Löschen verwenden (bevorzugt)
#ifdef _WIN32
#include <windows.h>
void sicheres_passwort_löschen(char *password, size_t len) {
SecureZeroMemory(password, len); // Windows API, wird nie optimiert
}
#else
// POSIX: explicit_bzero verwenden (glibc 2.25+, FreeBSD, OpenBSD)
void sicheres_passwort_löschen(char *password, size_t len) {
explicit_bzero(password, len); // Garantiert nicht optimiert zu werden
}
#endif
// Methode 3: Memory-Barrier-Ansatz
void sicheres_passwort_löschen_barrier(char *password, size_t len) {
memset(password, 0, len);
// Compiler-Barrier verhindert Neuordnung/Eliminierung
__asm__ __volatile__("" : : "r"(password) : "memory");
}
// Sicher: Retpoline-Mitigation für indirekte Branches
// Verhindert Spectre Variante 2 (Branch Target Injection)
// Retpoline-Thunk - fängt spekulative Ausführung in Endlosschleife
#define RETPOLINE_THUNK(reg) \
__asm__ __volatile__( \
"call .LSPEC_TRAP_%=\n" \
".LPAUSE_%=:\n" \
"pause\n" \
"lfence\n" \
"jmp .LPAUSE_%=\n" \
".LSPEC_TRAP_%=:\n" \
"mov %%" reg ", (%%rsp)\n" \
"ret\n" \
: : : "memory" \
)
// Moderne Compiler bieten eingebaute Retpoline-Unterstützung
// Kompilieren mit: -mretpoline -mretpoline-external-thunk
void sicherer_indirekter_aufruf(void (*func_ptr)(void)) {
// Mit Retpoline-Kompilierung sind indirekte Aufrufe sicher
// Spekulative Ausführung wird gefangen, nicht ausnutzbar
func_ptr();
}
// Sicher: Konstant-zeitlicher Vergleich resistent gegen Spekulation
#include <stdint.h>
#include <x86intrin.h>
int sicherer_konstant_zeit_vergleich(const uint8_t *a, const uint8_t *b, size_t len) {
// Spekulationsbarriere am Funktionseintritt einfügen
_mm_lfence();
volatile uint8_t result = 0;
for (size_t i = 0; i < len; i++) {
// XOR akkumuliert Unterschiede ohne Verzweigung
result |= a[i] ^ b[i];
// Optional: lfence in Schleife für zusätzliche Sicherheit einfügen
// (kann Leistung erheblich beeinträchtigen)
}
// Barrier vor Rückgabe des Ergebnisses
_mm_lfence();
// In Boolean konvertieren: 0 wenn gleich, 1 wenn unterschiedlich
// Arithmetik verwenden, um Branch zu vermeiden
return (int)((result | (~result + 1)) >> 7);
}
Ausgenutzt in der Praxis
Spectre und Meltdown (2018)
Diese Schwachstellen wurden von Google Project Zero und anderen Forschern entdeckt und betrafen praktisch alle modernen Prozessoren. Sie ermöglichten das Lesen von Kernel-Speicher aus nicht privilegierten Prozessen.
Intel-Prozessor-Schwachstellen (2018-2020)
Mehrere Varianten von spekulativen Ausführungsangriffen wurden bei Intel-Prozessoren entdeckt, darunter L1TF, MDS und TAA.
AMD-Prozessor-Schwachstellen (2021)
AMD-Prozessoren waren ebenfalls von spekulativen Ausführungsangriffen betroffen, obwohl in geringerem Ausmaß als Intel.
Tools zum Testen und Ausnutzen
-
spectre-meltdown-checker - Prüft Linux-Systeme auf Spectre/Meltdown-Mitigationen.
-
Intel MDS Tool - Intel Microarchitectural Data Sampling Prüfung.
-
Compiler Explorer - Zur Analyse, ob sicherheitskritischer Code wegoptimiert wird.
CVE-Beispiele
-
CVE-2017-5753 - Spectre Variante 1 - Bounds Check Bypass durch spekulative Ausführung.
-
CVE-2017-5715 - Spectre Variante 2 - Branch Target Injection, das indirekte Branches ausnutzt.
-
CVE-2017-5754 - Meltdown - Rogue Data Cache Load ermöglicht Kernel-Speicher-Lesen aus Userspace.
-
CVE-2018-3639 - Speculative Store Bypass (Spectre Variante 4).
-
CVE-2019-1125 - SWAPGS-Angriff - Spectre-Variante, die Windows betrifft.
Referenzen
-
MITRE Corporation. "CWE-1037: Processor Optimization Removal or Modification of Security-critical Code." https://cwe.mitre.org/data/definitions/1037.html
-
Kocher, P. et al. "Spectre Attacks: Exploiting Speculative Execution." https://spectreattack.com/
-
Lipp, M. et al. "Meltdown: Reading Kernel Memory from User Space." https://meltdownattack.com/
-
Intel. "Deep Dive: Intel Analysis of Speculative Execution Side Channels." https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance.html