Google 致力于为黑人社区推动种族平等。查看具体举措
此页面由 Cloud Translation API 翻译。
Switch to English

AddressSanitizer

AddressSanitizer (ASan) ist ein schnelles Compiler-basiertes Tool zum Erkennen von Speicherfehlern in nativem Code.

ASan erkennt:

  • Überlauf / Unterlauf des Stapel- und Haufenpuffers
  • Haufen nach kostenlos verwenden
  • Stapelverwendung außerhalb des Anwendungsbereichs
  • Double Free / Wild Free

ASan läuft sowohl auf 32-Bit- als auch auf 64-Bit-ARM sowie auf x86 und x86-64. Der CPU-Overhead von ASan beträgt ungefähr 2x, der Overhead für die Codegröße liegt zwischen 50% und 2x und der Speicherbedarf ist groß (abhängig von Ihren Zuordnungsmustern, jedoch in der Größenordnung von 2x).

Android 10 und der AOSP-Hauptzweig auf AArch64 unterstützen hardwarebeschleunigtes ASan (HWASan) , ein ähnliches Tool mit geringerem RAM-Overhead und einer größeren Anzahl erkannter Fehler. HWASan erkennt die Stapelverwendung nach der Rückgabe zusätzlich zu den von ASan erkannten Fehlern.

HWASan hat einen ähnlichen CPU- und Code-Overhead, aber einen viel geringeren RAM-Overhead (15%). HWASan ist nicht deterministisch. Es gibt nur 256 mögliche Tag-Werte, daher besteht eine flache Wahrscheinlichkeit von 0,4%, dass ein Fehler übersehen wird. HWASan verfügt nicht über die begrenzten roten Zonen von ASan zum Erkennen von Überläufen und die Quarantäne mit begrenzter Kapazität zum Erkennen von Nutzungsnachfällen. Daher spielt es für HWASan keine Rolle, wie groß der Überlauf ist oder wie lange der Speicher freigegeben wurde. Dies macht HWASan besser als ASan. Sie können mehr über das Design von HWASan oder über die Verwendung von HWASan auf Android lesen .

ASan erkennt neben Heap-Überläufen auch Stapel- / globale Überläufe und ist schnell bei minimalem Speicheraufwand.

In diesem Dokument wird beschrieben, wie Sie Teile / ganz Android mit ASan erstellen und ausführen. Wenn Sie eine SDK / NDK-App mit ASan erstellen, lesen Sie stattdessen Address Sanitizer .

Bereinigung einzelner ausführbarer Dateien mit ASan

Fügen LOCAL_SANITIZE:=address der Erstellungsregel für die ausführbare Datei LOCAL_SANITIZE:=address oder sanitize: { address: true } . Sie können den Code nach vorhandenen Beispielen durchsuchen oder nach anderen verfügbaren Desinfektionsmitteln suchen.

Wenn ein Fehler erkannt wird, druckt ASan einen ausführlichen Bericht sowohl an die Standardausgabe als auch an logcat und stürzt dann den Prozess ab.

Gemeinsame Bibliotheken mit ASan bereinigen

Aufgrund der Funktionsweise von ASan kann eine mit ASan erstellte Bibliothek nur von einer ausführbaren Datei verwendet werden, die mit ASan erstellt wurde.

Um eine gemeinsam genutzte Bibliothek zu bereinigen, die in mehreren ausführbaren Dateien verwendet wird, von denen nicht alle mit ASan erstellt wurden, benötigen Sie zwei Kopien der Bibliothek. Die empfohlene Methode hierfür besteht darin, Android.mk für das Android.mk Modul Folgendes Android.mk :

LOCAL_SANITIZE:=address
LOCAL_MODULE_RELATIVE_PATH := asan

Dadurch wird die Bibliothek in /system/lib/asan anstelle von /system/lib /system/lib/asan . Führen Sie dann Ihre ausführbare Datei aus mit:

LD_LIBRARY_PATH=/system/lib/asan

/init.rc /init.$device$.rc für /init.rc Folgendes in den entsprechenden Abschnitt von /init.rc oder /init.$device$.rc .

setenv LD_LIBRARY_PATH /system/lib/asan

/system/lib/asan dass der Prozess Bibliotheken aus /system/lib/asan wenn diese vorhanden sind, indem Sie /proc/$PID/maps lesen. Wenn dies nicht der Fall ist, 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 Stapelspuren

ASan verwendet einen schnellen, auf Frame-Zeigern basierenden Abwickler, um eine Stapelverfolgung für jedes Speicherzuweisungs- und Freigabeereignis im Programm aufzuzeichnen. Der größte Teil von Android wird ohne Frame-Zeiger erstellt. Infolgedessen erhalten Sie häufig nur ein oder zwei aussagekräftige Frames. Um dies zu beheben, erstellen Sie die Bibliothek entweder mit ASan (empfohlen!) Oder mit:

LOCAL_CFLAGS:=-fno-omit-frame-pointer
LOCAL_ARM_MODE:=arm

Oder setzen Sie ASAN_OPTIONS=fast_unwind_on_malloc=0 in der Prozessumgebung. Letzteres kann je nach Auslastung sehr CPU-intensiv sein.

Symbolisierung

Anfänglich enthalten ASan-Berichte Verweise auf Offsets in Binärdateien und gemeinsam genutzten Bibliotheken. Es gibt zwei Möglichkeiten, um Quelldatei- und Zeileninformationen abzurufen:

  • Stellen Sie sicher, dass die llvm-symbolizer Binärdatei in /system/bin . llvm-symbolizer wird aus Quellen in third_party/llvm/tools/llvm-symbolizer .
  • Filtern Sie den Bericht über das external/compiler-rt/lib/asan/scripts/symbolize.py Skript external/compiler-rt/lib/asan/scripts/symbolize.py .

Der zweite Ansatz kann aufgrund der Verfügbarkeit symbolisierter Bibliotheken auf dem Host mehr Daten (dh file:line Zeilenpositionen) bereitstellen.

ASan in Apps

ASan kann nicht in Java-Code sehen, aber es kann 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 ) . Dies ermöglicht ASan in allen Apps auf dem Gerät gleichzeitig, was eine hohe Belastung darstellt. Ein Gerät mit 2 GB RAM sollte dies jedoch verarbeiten können.

Fügen LOCAL_SANITIZE:=address der app_process in frameworks/base/cmds/app_process LOCAL_SANITIZE:=address frameworks/base/cmds/app_process . Ignorieren Sie app_process__asan Ziel app_process__asan in derselben Datei (falls es zum Zeitpunkt des Lesens noch vorhanden ist).

Bearbeiten Sie den Abschnitt " service zygote " der entsprechenden Datei " system/core/rootdir/init.zygote( 32|64 ).rc ", um dem Block eingerückter Zeilen mit der class main 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

Erstellen, ADB-Synchronisieren, Fastboot-Flash-Boot und Neustart.

Verwenden der Eigenschaft wrap

Der Ansatz im vorherigen Abschnitt fügt ASan in jede App im System ein (tatsächlich in jeden Nachkommen des Zygote-Prozesses). Es ist möglich, nur eine (oder mehrere) Apps mit ASan auszuführen, wobei ein gewisser Speicheraufwand gegen einen langsameren App-Start eingetauscht wird.

Dies kann erreicht werden, indem Sie Ihre App mit dem wrap. starten wrap. Eigentum. Im folgenden Beispiel wird die Google Mail-App unter ASan ausgeführt:

adb root
adb shell setenforce 0  # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"

In diesem Zusammenhang schreibt asanwrapper /system/bin/app_process in /system/bin/asan/app_process , das mit ASan erstellt wurde. Außerdem wird am Anfang des /system/lib/asan für dynamische Bibliotheken /system/lib/asan . Auf diese Weise werden ASan-instrumentierte Bibliotheken aus /system/lib/asan normalen Bibliotheken in /system/lib vorgezogen, wenn sie mit asanwrapper .

Wenn ein Fehler gefunden wird, stürzt die App ab und der Bericht wird im Protokoll gedruckt.

SANITIZE_TARGET

Android 7.0 und höher unterstützt die gleichzeitige Erstellung der gesamten Android-Plattform mit ASan. (Wenn Sie eine höhere Version als Android 9 erstellen, 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 Gruppen gemeinsam genutzter Bibliotheken erstellt: normal in /system/lib (der erste Make-Aufruf) und ASan-instrumentiert in /data/asan/lib (der zweite Make-Aufruf). Ausführbare Dateien aus dem zweiten Build überschreiben diejenigen aus dem ersten Build. Durch ASan instrumentierte ausführbare Dateien erhalten mithilfe von /system/bin/linker_asan in PT_INTERP einen anderen Bibliothekssuchpfad, der /data/asan/lib vor /system/lib PT_INTERP .

Das Build-System blockiert Zwischenobjektverzeichnisse, wenn sich der Wert von $SANITIZE_TARGET geändert hat. Dies erzwingt eine Neuerstellung aller Ziele unter Beibehaltung der installierten Binärdateien unter /system/lib .

Einige Ziele können mit ASan nicht erstellt werden:

  • Statisch verknüpfte ausführbare Dateien
  • LOCAL_CLANG:=false Ziele
  • LOCAL_SANITIZE:=false werden nicht für SANITIZE_TARGET=address

Ausführbare SANITIZE_TARGET wie diese werden im Build SANITIZE_TARGET übersprungen, und die Version vom ersten Aufruf von make bleibt in /system/bin .

Bibliotheken wie diese werden ohne ASan erstellt. Sie können ASan-Code aus den statischen Bibliotheken enthalten, von denen sie abhängen.

Unterstützende Dokumentation