AddressSanitizer-Schattenbytes

Wir fassen kurz das Konzept von Schattenbytes zusammen und wie sie von der Laufzeitimplementierung verwendet /fsanitize=addresswerden können. Weitere Details finden Sie im seminalen Papier und im AddressSanitizer-Algorithmus.

Kernkonzept

Alle 8 Bytes im virtuellen Adressbereich Ihrer Anwendung können mithilfe eines Schattenbytes beschrieben werden.

Ein Schattenbyte beschreibt, wie viele Bytes derzeit wie folgt zugänglich sind:

  • 0 bedeutet alle 8 Bytes
  • 1-7 bedeutet ein bis sieben Bytes
  • Negative Zahlen codieren den Kontext für die Laufzeit, die für die Berichtsdiagnose verwendet werden soll.

Schattenbytelegende

Betrachten Sie diese Schattenbytelegende, in der alle negativen Zahlen definiert sind:

Screenshot of the AddressSanitizer shadow-byte legend.

Zuordnung – Beschreiben des Adressraums

Jeder 8 Bytes im virtuellen Adressbereich der Anwendung, der "0-mod-8" ausgerichtet ist, kann dem Schattenbyte zugeordnet werden, der diesen Platz im virtuellen Adressbereich beschreibt. Diese Zuordnung kann mit einer einfachen Schicht erreicht und hinzugefügt werden.

Auf x86:

char shadow_byte_value = *((Your_Address >> 3) + 0x30000000)

Auf x64:

char shadow_byte_value = *((Your_Address >> 3) + _asan_runtime_assigned_offset)

Codegenerierung – Tests

Überlegen Sie, wie bestimmte Schattenbytes entweder vom Compiler generierten Code, statischen Daten oder der Laufzeit geschrieben werden. Dieser Pseudocode zeigt, wie es möglich ist, eine Überprüfung zu generieren, die vor jedem Laden oder Speichern steht:

ShadowAddr = (Addr >> 3) + Offset;
if (*ShadowAddr != 0) {
    ReportAndCrash(Addr);
}

Bei der Instrumentierung eines Speicherbezugs, der kleiner als 8 Bytes breit ist, ist die Instrumentierung etwas komplexer. Wenn der Schattenwert positiv ist (d. h. nur die ersten k Bytes im 8-Byte-Wort können zugegriffen werden), müssen wir die letzten 3 Bits der Adresse mit k vergleichen.

ShadowAddr = (Addr >> 3) + Offset;
k = *ShadowAddr;
if (k != 0 && ((Addr & 7) + AccessSize > k)) {
    ReportAndCrash(Addr);
}

Die Laufzeit und der vom Compiler generierte Code schreiben beide Schattenbytes. Diese Schattenbytes erlauben oder widerrufen den Zugriff, wenn Bereiche enden oder speicherfrei sind. Die obigen Überprüfungen lesen Schattenbytes, die 8 Byte "Slots" im Adressbereich Ihrer Anwendung beschreiben, zu einem bestimmten Zeitpunkt in der Ausführung des Programms. Neben diesen explizit generierten Prüfungen überprüft die Laufzeit auch Schattenbytes, nachdem sie viele Funktionen im CRT abfangen (oder "Hooks").

Weitere Informationen finden Sie in der Liste der abgefangenen Funktionen.

Festlegen von Schattenbytes

Sowohl der Code, den der Compiler generiert, als auch die AddressSanitizer-Laufzeit kann Schattenbytes schreiben. Der Compiler kann z. B. Schattenbytes festlegen, um den Zugriff auf lokale Stapel zu ermöglichen, die in einem inneren Bereich definiert sind. Die Laufzeit kann globale Variablen im Datenabschnitt mit Schattenbytes umgeben.

Siehe auch

Übersicht über AddressSanitizer
Bekannte Probleme von AddressSanitizer
Kompilierungs- und Sprachreferenz für AddressSanitizer
Runtimereferenz für AddressSanitizer
AddressSanitizer-Tests in der Cloud oder verteilten Umgebungen
Integration des AddressSanitizer-Debuggers
AddressSanitizer-Fehlerbeispiele