AddressSanitizer-Schattenbytes

Wir fassen das Konzept von Schattenbytes kurz zusammen und beschreiben, wie sie von der Laufzeitimplementierungen von verwendet werden /fsanitize=address können. Weitere Informationen finden Sie im Seminal Paper und im AddressSanitizer-Algorithmus.

Kernkonzept

Alle 8 Bytes im virtuellen Adressraum Ihrer Anwendung können mit einem Schattenbytebeschrieben werden.

Ein Schattenbyte beschreibt wie folgt, auf wie viele Bytes derzeit zugegriffen werden kann:

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

Schatten bytelegende

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

Screenshot of the AddressSanitizer shadow-byte legend.

Zuordnung: Beschreiben Des Adressraums

Alle 8 Bytes im virtuellen Adressraum der Anwendung, der "0-mod-8" ausgerichtet ist, können dem Schattenbyte zugeordnet werden, das diesen Slot im virtuellen Adressraum beschreibt. Diese Zuordnung kann mit einer einfachen Verschiebungdurchgeführt werden 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 durch den vom Compiler generierten Code, statische Daten oder die Laufzeit geschrieben werden können. Dieser Pseudocode zeigt, wie es möglich ist, eine Überprüfung zu generieren, die jedem Laden oder Speichern vorausgeht:

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

Beim Instrumentieren eines Speicherverweis, der weniger als 8 Bytes breit ist, ist die Instrumentierung etwas komplexer. Wenn der Schattenwert positiv ist (d. h. nur auf die ersten k Bytes im 8-Byte-Wort zugegriffen werden kann), 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);
}

Sowohl die Laufzeit als auch der vom Compiler generierte Code schreiben Schattenbytes. Diese Schattenbytes ermöglichen oder widerrufen den Zugriff, wenn Bereiche enden oder Speicher freigegeben werden. Die obigen Überprüfungen lesen Schattenbytes, die 8-Byte-"Slots" im Adressraum Ihrer Anwendung beschreiben, zu einem bestimmten Zeitpunkt in der Programmausführung. Neben diesen explizit generierten Überprüfungen überprüft die Laufzeit auch Schattenbytes, nachdem viele Funktionen in der CRT abgefangen (oder "hooks") wurden.

Weitere Informationen finden Sie in der Liste der abgefangenen Funktionen.

Festlegen von Schattenbytes

Sowohl der vom Compiler generierte Code als auch die AddressSanitizer-Runtime können Schattenbytes schreiben. Beispielsweise kann der Compiler Schattenbytes festlegen, um Zugriff in fester Größe auf Stapellokale zu ermöglichen, die in einem inneren Bereich definiert sind. Die Runtime kann globale Variablen im Datenabschnitt mit Schattenbytes umschließen.

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