AddressSanitizer (ASan) ist ein schnelles compilerbasiertes Tool zum Erkennen von Speicherfehlern in nativem Code.
ASan erkennt:
- Stack- und Heap-Pufferüberlauf/-unterlauf
- Heap-Nutzung nach dem Freigeben
- Stack außerhalb des Gültigkeitsbereichs verwendet
- Doppeltes Freibad/Wildtreffer
ASan wird sowohl auf 32-Bit- als auch auf 64-Bit-ARM- sowie auf x86- und x86-64-Systemen ausgeführt. Der CPU-Overhead von ASan ist etwa doppelt so hoch, der Codegrößen-Overhead liegt zwischen 50 % und dem Doppelten und es gibt einen großen Arbeitsspeicher-Overhead (je nach Allokationsmuster, aber in der Größenordnung von 2 x).
Android 10 und der AOSP-Hauptzweig auf AArch64 unterstützen Hardware-assisted AddressSanitizer (HWASan), ein ähnliches Tool mit geringerem RAM-Overhead und einer größeren Bandbreite an erkannten Fehlern. HWASan erkennt die Stacknutzung nach der Rückgabe zusätzlich zu den von ASan erkannten Fehlern.
HWASan hat einen ähnlichen CPU- und Codegrößenaufwand, aber einen viel geringeren RAM-Aufwand (15%). HWASan ist nicht deterministisch. Es gibt nur 256 mögliche Tag-Werte, sodass die Wahrscheinlichkeit, dass ein Fehler übersehen wird, bei 0,4 % liegt. HWASan hat nicht die begrenzten roten Zonen von ASan zum Erkennen von Überläufen und die Quarantäne mit begrenzter Kapazität zum Erkennen von „Use-After-Free“. Daher spielt es für HWASan keine Rolle, wie groß der Überlauf ist oder wie lange es her ist, dass der Arbeitsspeicher deaktiviert wurde. Dadurch ist HWASan besser als ASan. Weitere Informationen zum Design von HWASan oder zur Verwendung von HWASan auf Android-Geräten
ASan erkennt neben Heap-Overflows auch Stack-/globale Overflows und ist schnell mit minimalem Arbeitsspeicheraufwand.
In diesem Dokument wird beschrieben, wie Teile bzw. das gesamte Android-Betriebssystem mit ASan erstellt und ausgeführt wird. Wenn Sie eine SDK-/NDK-App mit ASan erstellen, lesen Sie stattdessen den Hilfeartikel Address Sanitizer.
Einzelne ausführbare Dateien mit ASan bereinigen
Fügen Sie der Build-Regel für die ausführbare Datei LOCAL_SANITIZE:=address
oder sanitize: { address: true }
hinzu. Sie können im Code nach vorhandenen Beispielen oder nach den anderen verfügbaren Sanitizern suchen.
Wenn ein Fehler erkannt wird, druckt ASan sowohl in der Standardausgabe als auch in logcat
einen ausführlichen Bericht aus und stürzt den Prozess ab.
Gemeinsam genutzte Bibliotheken mit ASan bereinigen
Aufgrund der Funktionsweise von ASan kann eine mit ASan erstellte Bibliothek nur von einer mit ASan erstellten ausführbaren Datei verwendet werden.
Zum Bereinigen einer gemeinsam genutzten Bibliothek, die in mehreren ausführbaren Dateien verwendet wird und nicht alle mit ASan erstellt wird, benötigen Sie zwei Kopien der Bibliothek. Wir empfehlen, Folgendes zu Android.mk
für das betreffende Modul hinzuzufügen:
LOCAL_SANITIZE:=address LOCAL_MODULE_RELATIVE_PATH := asan
Dadurch wird die Bibliothek in /system/lib/asan
statt in /system/lib
abgelegt. Führen Sie dann die ausführbare Datei mit folgendem Befehl aus:
LD_LIBRARY_PATH=/system/lib/asan
Fügen Sie für System-Daemons dem entsprechenden Abschnitt von /init.rc
oder /init.$device$.rc
Folgendes hinzu:
setenv LD_LIBRARY_PATH /system/lib/asan
Prüfen Sie, ob der Prozess Bibliotheken von /system/lib/asan
verwendet, sofern vorhanden. Lesen Sie dazu /proc/$PID/maps
. Andernfalls müssen Sie möglicherweise SELinux deaktivieren:
adb root
adb shell setenforce 0
# restart the process with adb shell kill $PID # if it is a system service, or may be adb shell stop; adb shell start.
Bessere Stacktraces
ASan verwendet einen schnellen, auf dem Frame-Pointer basierenden Unwinder, um für jedes Ereignis der Speicherzuweisung und ‑entfernung im Programm einen Stack-Trace aufzuzeichnen. Die meisten Android-Versionen enthalten keine Frame-Pointer. Infolgedessen erhalten Sie oft nur ein oder zwei aussagekräftige Frames. Um das Problem zu beheben, können Sie die Bibliothek entweder mit ASan (empfohlen) oder mit einem der folgenden Tools neu erstellen:
LOCAL_CFLAGS:=-fno-omit-frame-pointer LOCAL_ARM_MODE:=arm
Sie können auch ASAN_OPTIONS=fast_unwind_on_malloc=0
in der Prozessumgebung festlegen. Letztere kann je nach Last sehr CPU-intensiv sein.
Symbolisierung
Ursprünglich enthalten ASan-Berichte Verweise auf Abweichungen in Binärdateien und freigegebenen Bibliotheken. Es gibt zwei Möglichkeiten, Informationen zur Quelldatei und zur Zeile abzurufen:
- Prüfen Sie, ob die
llvm-symbolizer
-Binärdatei in/system/bin
vorhanden ist.llvm-symbolizer
wird aus Quellen inthird_party/llvm/tools/llvm-symbolizer
erstellt. - Filtern Sie den Bericht mit dem
external/compiler-rt/lib/asan/scripts/symbolize.py
-Script.
Der zweite Ansatz kann aufgrund der Verfügbarkeit symbolisierter Bibliotheken auf dem Host mehr Daten (d. h. file:line
-Standorte) liefern.
Asana in Apps
ASan kann keinen Java-Code sehen, aber Fehler in den JNI-Bibliotheken erkennen. Dazu müssen Sie die ausführbare Datei mit ASan erstellen, in diesem Fall /system/bin/app_process(32|64)
. Dadurch wird ASan in allen Apps auf dem Gerät gleichzeitig aktiviert. Das ist eine hohe Belastung, aber ein Gerät mit 2 GB RAM sollte damit umgehen können.
Fügen Sie der Build-Regel app_process
in frameworks/base/cmds/app_process
LOCAL_SANITIZE:=address
hinzu. Ignorieren Sie vorerst das Ziel app_process__asan
in derselben Datei, wenn es zum Zeitpunkt des Lesens noch vorhanden ist.
Bearbeiten Sie den Abschnitt service zygote
der entsprechenden system/core/rootdir/init.zygote(32|64).rc
-Datei, um dem Block mit den eingerückten Zeilen, die class main
enthalten, die folgenden Zeilen hinzuzufügen, die ebenfalls um denselben Betrag eingerückt sind:
setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib setenv ASAN_OPTIONS allow_user_segv_handler=true
Build, ADB-Synchronisierung, Fastboot Flash Boot und Neustart.
Das Attribut „umbruch“ verwenden
Mit dem Ansatz im vorherigen Abschnitt wird ASan in jede Anwendung im System eingefügt (tatsächlich in jeden Nachfolger des Zygote-Prozesses). Es ist möglich, nur eine (oder mehrere) Apps mit ASan auszuführen und einen gewissen Speicheroverhead für ein langsameres App-Starten in Kauf zu nehmen.
Sie können dazu die Property wrap.
verwenden.
Im folgenden Beispiel wird die Gmail App unter ASan ausgeführt:
adb root
adb shell setenforce 0 # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"
In diesem Kontext schreibt asanwrapper
/system/bin/app_process
in /system/bin/asan/app_process
um, das mit ASan erstellt wird. Außerdem wird /system/lib/asan
an den Anfang des Suchpfads der dynamischen Bibliothek eingefügt. So werden ASan-instrumentierte Bibliotheken aus /system/lib/asan
bei der Ausführung mit asanwrapper
normalen Bibliotheken in /system/lib
vorgezogen.
Wenn ein Fehler gefunden wird, stürzt die App ab und der Bericht wird in das Protokoll gedruckt.
SANITIZE_TARGET
Android 7.0 und höher unterstützen das Erstellen der gesamten Android-Plattform mit ASan auf einmal. Wenn Sie eine Version entwickeln, die höher als Android 9 ist, ist HWASan die bessere Wahl.
Führen Sie die folgenden Befehle im selben Build-Baum aus.
make -j42
SANITIZE_TARGET=address make -j42
In diesem Modus enthält userdata.img
zusätzliche Bibliotheken und muss ebenfalls auf das Gerät geflasht werden. Verwenden Sie die folgende Befehlszeile:
fastboot flash userdata && fastboot flashall
Dadurch werden zwei gemeinsam genutzte Bibliotheken erstellt: eine normale in /system/lib
(die erste make-Aufruf) und eine mit ASan instrumentierte in /data/asan/lib
(die zweite make-Aufruf). Ausführbare Dateien aus dem zweiten Build überschreiben die aus dem ersten Build. ASan-instrumentierte ausführbare Dateien erhalten einen anderen Bibliothekssuchpfad, der /data/asan/lib
vor /system/lib
enthält. Dazu wird /system/bin/linker_asan
in PT_INTERP
verwendet.
Das Build-System überschreibt Zwischenobjektverzeichnisse, wenn sich der Wert von $SANITIZE_TARGET
geändert hat. Dadurch wird ein Neuaufbau aller Ziele erzwungen, während die installierten Binärdateien unter /system/lib
erhalten bleiben.
Einige Ziele können nicht mit ASan erstellt werden:
- Statisch verknüpfte ausführbare Dateien
LOCAL_CLANG:=false
ZielvorhabenLOCAL_SANITIZE:=false
sind nicht fürSANITIZE_TARGET=address
geeignet
Solche ausführbaren Dateien werden im SANITIZE_TARGET
-Build übersprungen und die Version aus dem ersten „make“-Aufruf bleibt in /system/bin
.
Solche Bibliotheken werden ohne ASan erstellt. Sie können ASan-Code aus den statischen Bibliotheken enthalten, von denen sie abhängig sind.