GWP-ASan

GWP-ASan ist eine native Funktion zur Arbeitsspeicherzuweisung, Use-After-Free und Heap-Buffer-Overflow Bugs. Der informelle Name ist ein rekursives Akronym: GWP-ASan Will. Sollstandort-SANität angeben. „Mag ich“-Bewertung entfernen HWASan oder Malloc Debug (Fehlerbehebung) GWP-ASan erfordert keine Quelle und keine Neukompilierung, d. h., vorgefertigt) und funktioniert sowohl mit 32- als auch 64-Bit-Prozessen (allerdings stürzt 32-Bit ab) weniger Debugging-Informationen. In diesem Artikel werden die Maßnahmen beschrieben, die Sie ergreifen müssen, um diese Funktion in Ihrem GWP-ASan ist für Apps verfügbar, die auf Android 11 (API-Level 30) oder höher ausgerichtet sind.

Übersicht

GWP-ASan ist auf einigen zufällig ausgewählten Systemanwendungen und Plattformen aktiviert Ausführbare Dateien beim Start des Prozesses (oder wenn sich die Zygote verzweigt). GWP-ASan aktivieren in Ihre eigene App, um speicherbezogene Fehler zu finden und Ihre App auf Unterstützung für ARM Memory Tagging Extension (MTE). Die Mechanismen zur Stichprobenerhebung bei der Zuordnung bieten auch Zuverlässigkeit gegenüber Todesfragen.

Nach der Aktivierung fängt GWP-ASan eine zufällig ausgewählte Teilmenge von Heap-Zuweisungen ab. und platziert sie in einer speziellen Region, in der schwer aufzuspürende und Fehler von Speicherbeschädigungen. Wenn genügend Nutzer vorhanden sind, wird selbst diese niedrige Heap-Memory-Sicherheitsfehler finden, die bei regulären Tests nicht gefunden werden. Zum Beispiel hat GWP-ASan eine beträchtliche Anzahl von Fehlern (Viele davon befinden sich noch in der eingeschränkten Ansicht.)

GWP-ASan sammelt zusätzliche Informationen über alle Zuweisungen, abgefangen. Diese Informationen sind verfügbar, wenn GWP-ASan eine Arbeitsspeichersicherheit erkennt und wird automatisch in den nativen Absturzbericht aufgenommen, die bei der Fehlerbehebung wesentlich helfen (siehe Beispiel).

GWP-ASan ist darauf ausgelegt, keinen nennenswerten CPU-Aufwand zu verursachen. GWP-ASan führt zu einem geringen, festen RAM-Overhead, wenn er aktiviert ist. Dieser Mehraufwand wird durch Android-System und beläuft sich derzeit auf etwa 70 Kibibyte (KiB) pro betroffen sind.

App aktivieren

GWP-ASan kann von Anwendungen pro Prozessebene mithilfe des android:gwpAsanMode-Tag im App-Manifest ein. Die folgenden Optionen sind unterstützt:

  • Immer deaktiviert (android:gwpAsanMode="never"): Diese Einstellung ist vollständig deaktiviert. deaktiviert GWP-ASan in Ihrer App und ist die Standardeinstellung für systemfremde Apps.

  • Standard (android:gwpAsanMode="default" oder nicht angegeben): Android 13 (API) Ebene 33) und niedriger: GWP-ASan ist deaktiviert. Android 14 (API-Level 34) und höher: Wiederherstellbarer GWP-ASan ist aktiviert.

  • Immer aktiviert (android:gwpAsanMode="always"): Diese Einstellung aktiviert GWP-ASan in Ihrer App. Dies umfasst Folgendes:

    1. Das Betriebssystem reserviert eine feste Menge an RAM für GWP-ASan Vorgänge mit etwa ~70 KiB für jeden betroffenen Prozess. (Aktivieren GWP-ASan, wenn Ihre Anwendung nicht kritisch empfindlich auf Speichererweiterungen reagiert. Nutzung.)

    2. GWP-ASan fängt eine zufällig ausgewählte Teilmenge von Heap-Zuweisungen ab werden sie in einer speziellen Region platziert, in der die Speichersicherheit zuverlässig erkannt wird. Verstöße.

    3. Wenn in der speziellen Region ein Verstoß gegen die Sicherheit des Arbeitsspeichers auftritt, GWP-ASan bricht den Prozess ab.

    4. GWP-ASan stellt zusätzliche Informationen zum Fehler im Absturz bereit. Bericht.

Um GWP-ASan global für Ihre App zu aktivieren, fügen Sie Folgendes zu Ihrem AndroidManifest.xml-Datei:

<application android:gwpAsanMode="always">
  ...
</application>

Darüber hinaus kann GWP-ASan explizit für bestimmte Unterprozesse der App. Sie können ein Targeting auf Aktivitäten und Dienste mithilfe von Prozessen vornehmen die explizit für GWP-ASan aktiviert oder deaktiviert sind. Im Folgenden finden Sie Beispiel:

<application>
  <processes>
    <!-- Create the (empty) application process -->
    <process />

    <!-- Create subprocesses with GWP-ASan both explicitly enabled and disabled. -->
    <process android:process=":gwp_asan_enabled"
               android:gwpAsanMode="always" />
    <process android:process=":gwp_asan_disabled"
               android:gwpAsanMode="never" />
  </processes>

  <!-- Target services and activities to be run on either the GWP-ASan enabled or disabled processes. -->
  <activity android:name="android.gwpasan.GwpAsanEnabledActivity"
            android:process=":gwp_asan_enabled" />
  <activity android:name="android.gwpasan.GwpAsanDisabledActivity"
            android:process=":gwp_asan_disabled" />
  <service android:name="android.gwpasan.GwpAsanEnabledService"
           android:process=":gwp_asan_enabled" />
  <service android:name="android.gwpasan.GwpAsanDisabledService"
           android:process=":gwp_asan_disabled" />
</application>

Wiederherstellbarer GWP-ASan

Android 14 (API-Level 34) und höher unterstützen wiederherstellbaren GWP-ASan, finden Heap-Buffer-Overflow- und Heap-Use-After-Free-Fehler in ohne die Nutzererfahrung zu beeinträchtigen. Wenn android:gwpAsanMode gleich nicht in einer AndroidManifest.xml angegeben ist, verwendet die Anwendung wiederherstellbar GWP-ASan.

Der wiederherstellbare GWP-ASan unterscheidet sich in folgenden Punkten vom Basis-GWP-ASan:

  1. Wiederherstellbarer GWP-ASan ist nur bei etwa 1% der App-Starts aktiviert. als bei jedem App-Start.
  2. Wenn ein Heap-Use-After-Free- oder Heap-Buffer-Overflow-Fehler erkannt wird, wird dieser Fehler im Absturzbericht (Tombstone) angezeigt. Dieser Absturzbericht ist verfügbar über die ActivityManager#getHistoricalProcessExitReasons API, die dem ursprünglichen GWP-ASan entspricht.
  3. Statt nach dem Speichern des Absturzberichts die Anwendung zu beenden, ermöglicht eine Speicherbeschädigung und die Anwendung wird weiter ausgeführt. Der Vorgang kann wie gewohnt fortgesetzt werden, das Verhalten der App ist jedoch nicht mehr betroffen. angegeben ist. Aufgrund der Speicherbeschädigung kann die App beliebig oft abstürzen. oder in Zukunft ohne sichtbare Auswirkungen für den Nutzer fortgesetzt wird.
  4. Der wiederherstellbare GWP-ASan wird nach dem Erstellen des Absturzberichts deaktiviert. Dementsprechend wird Eine App kann pro App-Start nur einen einzigen wiederherstellbaren GWP-ASan-Bericht erhalten.
  5. Wenn ein benutzerdefinierter Signal-Handler in der App installiert ist, wird er nie für ein SIGSEGV-Signal, das auf einen wiederherstellbaren GWP-ASan-Fehler hindeutet.

Da wiederherstellbare GWP-ASan-Abstürze auf echte Arbeitsspeicherinstanzen hinweisen auf Endnutzergeräten beschädigt werden, empfehlen wir dringend, mit hoher Priorität identifiziert wurde.

Entwicklersupport

In diesen Abschnitten werden Probleme beschrieben, die bei der Verwendung von GWP-ASan auftreten können und wie Sie und sie anzugehen.

Zuordnungs-/Weiterleitungs-Traces fehlen

Wenn Sie einen nativen Absturz diagnostizieren, der offenbar fehlt -Frames für die Zuweisung/Abgabe. Ihre Anwendung fehlt wahrscheinlich Frame-Cursor. GWP-ASan verwendet Framezeiger, um die Zuordnung und die Freigabe aus Leistungsgründen und kann den Stacktrace nicht auflösen, wenn vorhanden ist.

Framepointer sind für „arm64“-Geräte standardmäßig aktiviert und für „arm32“ standardmäßig deaktiviert Geräte. Da Anwendungen keine Kontrolle über libc haben, ist es (im Allgemeinen) GWP-ASan kann keine Traces für die Zuweisung/Deallocation für 32-Bit erfassen. ausführbare Dateien oder Apps. 64-Bit-Anwendungen sollten darauf achten, dass sie nicht mit -fomit-frame-pointer erstellt, damit GWP-ASan Stacktraces der Deallocation.

Sicherheitsverstöße reproduzieren

GWP-ASan wurde entwickelt, um Verstöße gegen die Heap-Speicher-Sicherheit auf Nutzergeräten zu erkennen. GWP-ASan liefert so viel Kontext wie möglich zum Absturz (Zugriffs-Trace von den Verstoß und verursacht den String und die Traces für die Zuordnung/Freigabe. immer noch schwer zu erkennen, wie es zum Verstoß kam. Da der Fehler ist probabilistisch. Die Reproduzierung von GWP-ASan-Berichten auf einem auf einem lokalen Gerät.

Wenn der Fehler in diesen Fällen 64-Bit-Geräte betrifft, sollten Sie HWAddressSanitizer (HWASan). HWASan erkennt Arbeitsspeichersicherheit zuverlässig auf Stack-, Heap- und globalen Daten. Anwendung ausführen mit HWASan kann zuverlässig das gleiche Ergebnis reproduzieren, das von GWP-ASan.

In Fällen, in denen das Ausführen Ihrer Anwendung unter HWASan nicht ausreicht, der Ursache des Fehlers ist, Code mit fuzz versehen betroffene Website. Sie können Ihre Fuzzing-Bemühungen anhand der Informationen in den GWP-ASan-Bericht, mit dem der zugrunde liegende Code zuverlässig erkannt und offengelegt werden kann Probleme.

Beispiel

Dieser native Beispielcode hat einen Heap-Use-After-Free-Fehler:

#include <jni.h>
#include <string>
#include <string_view>

jstring native_get_string(JNIEnv* env) {
   std::string s = "Hellooooooooooooooo ";
   std::string_view sv = s + "World\n";

   // BUG: Use-after-free. `sv` holds a dangling reference to the ephemeral
   // string created by `s + "World\n"`. Accessing the data here is a
   // use-after-free.
   return env->NewStringUTF(sv.data());
}

extern "C" JNIEXPORT jstring JNICALL
Java_android11_test_gwpasan_MainActivity_nativeGetString(
    JNIEnv* env, jobject /* this */) {
  // Repeat the buggy code a few thousand times. GWP-ASan has a small chance
  // of detecting the use-after-free every time it happens. A single user who
  // triggers the use-after-free thousands of times will catch the bug once.
  // Alternatively, if a few thousand users each trigger the bug a single time,
  // you'll also get one report (this is the assumed model).
  jstring return_string;
  for (unsigned i = 0; i < 0x10000; ++i) {
    return_string = native_get_string(env);
  }

  return reinterpret_cast<jstring>(env->NewGlobalRef(return_string));
}

Bei einem Test mit dem Beispielcode oben konnte GWP-ASan erfolgreich den illegale Nutzung und hat den unten stehenden Absturzbericht ausgelöst. GWP-ASan hat automatisch den Bericht durch die Bereitstellung von Informationen über die Art des Absturzes, den Zuweisungsmetadaten und der zugehörige Zuweisungs- und Deallocation-Stack Spuren.

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'google/sargo/sargo:10/RPP3.200320.009/6360804:userdebug/dev-keys'
Revision: 'PVT1.0'
ABI: 'arm64'
Timestamp: 2020-04-06 18:27:08-0700
pid: 16227, tid: 16227, name: 11.test.gwpasan  >>> android11.test.gwpasan <<<
uid: 10238
signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x736ad4afe0
Cause: [GWP-ASan]: Use After Free on a 32-byte allocation at 0x736ad4afe0

backtrace:
      #00 pc 000000000037a090  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::ScopedCheck::CheckNonHeapValue(char, art::(anonymous namespace)::JniValueType)+448)
      #01 pc 0000000000378440  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::ScopedCheck::CheckPossibleHeapValue(art::ScopedObjectAccess&, char, art::(anonymous namespace)::JniValueType)+204)
      #02 pc 0000000000377bec  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::ScopedCheck::Check(art::ScopedObjectAccess&, bool, char const*, art::(anonymous namespace)::JniValueType*)+612)
      #03 pc 000000000036dcf4  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::CheckJNI::NewStringUTF(_JNIEnv*, char const*)+708)
      #04 pc 000000000000eda4  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (_JNIEnv::NewStringUTF(char const*)+40)
      #05 pc 000000000000eab8  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (native_get_string(_JNIEnv*)+144)
      #06 pc 000000000000edf8  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (Java_android11_test_gwpasan_MainActivity_nativeGetString+44)
      ...

deallocated by thread 16227:
      #00 pc 0000000000048970  /apex/com.android.runtime/lib64/bionic/libc.so (gwp_asan::AllocationMetadata::CallSiteInfo::RecordBacktrace(unsigned long (*)(unsigned long*, unsigned long))+80)
      #01 pc 0000000000048f30  /apex/com.android.runtime/lib64/bionic/libc.so (gwp_asan::GuardedPoolAllocator::deallocate(void*)+184)
      #02 pc 000000000000f130  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (std::__ndk1::_DeallocateCaller::__do_call(void*)+20)
      ...
      #08 pc 000000000000ed6c  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >::~basic_string()+100)
      #09 pc 000000000000ea90  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (native_get_string(_JNIEnv*)+104)
      #10 pc 000000000000edf8  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (Java_android11_test_gwpasan_MainActivity_nativeGetString+44)
      ...

allocated by thread 16227:
      #00 pc 0000000000048970  /apex/com.android.runtime/lib64/bionic/libc.so (gwp_asan::AllocationMetadata::CallSiteInfo::RecordBacktrace(unsigned long (*)(unsigned long*, unsigned long))+80)
      #01 pc 0000000000048e4c  /apex/com.android.runtime/lib64/bionic/libc.so (gwp_asan::GuardedPoolAllocator::allocate(unsigned long)+368)
      #02 pc 000000000003b258  /apex/com.android.runtime/lib64/bionic/libc.so (gwp_asan_malloc(unsigned long)+132)
      #03 pc 000000000003bbec  /apex/com.android.runtime/lib64/bionic/libc.so (malloc+76)
      #04 pc 0000000000010414  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (operator new(unsigned long)+24)
      ...
      #10 pc 000000000000ea6c  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (native_get_string(_JNIEnv*)+68)
      #11 pc 000000000000edf8  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (Java_android11_test_gwpasan_MainActivity_nativeGetString+44)
      ...

Weitere Informationen

Weitere Informationen zu den Implementierungsdetails von GWP-ASan finden Sie in der LLVM-Dokumentation Weitere Informationen Weitere Informationen zu nativen Absturzberichten für Android finden Sie unter Native Abstürze diagnostizieren.