GWP - San

GWP-ASan è una funzionalità nativa per l'allocazione della memoria che aiuta a trovare usa-dopo-senza costi e heap-buffer-overflow insetti. Il suo nome informale è un acronimo ricorsivo,"GWP-ASan Will Pornistra lllocation SAN. Non mi piace HWASan oppure Debug di Malloc, GWP-ASan non richiede l'origine o la ricompilazione (ovvero funziona con predefiniti) e funziona su processi sia a 32 che a 64 bit (anche se si verificano arresti anomali a 32 bit) contengono meno informazioni di debug). Questo argomento illustra le azioni da intraprendere per attivare questa funzionalità nei tuoi dell'app. GWP-ASan è disponibile sulle app destinate ad Android 11 (livello API 30) o versioni successive.

Panoramica

GWP-ASan è abilitato su alcune applicazioni di sistema e piattaforme selezionate in modo casuale eseguibili all'avvio del processo (o quando lo zigote crea forchette). Attiva GWP-ASan in la tua app per aiutarti a trovare bug relativi alla memoria e per prepararla per Supporto per le estensioni MTE (Memory Tagging Extension) ARM. I meccanismi di campionamento all'allocazione offrono inoltre affidabilità query di morte.

Una volta abilitato, GWP-ASan intercetta un sottoinsieme scelto casualmente di allocazioni di heap, e li colloca in una regione speciale che rileva heap difficili da rilevare o errori di corruzione della memoria. Se viene fornito un numero sufficiente di utenti, anche questa bassa frequenza di campionamento Trovare bug di sicurezza della memoria heap che non vengono trovati tramite test regolari. Ad esempio, GWP-ASan ha trovato un numero significativo di bug nel browser Chrome (molti dei quali sono ancora con visualizzazione limitata).

GWP-ASan raccoglie ulteriori informazioni su tutte le allocazioni che intercettazioni. Queste informazioni sono disponibili quando GWP-ASan rileva una sicurezza della memoria violazione e viene automaticamente inserita nel report nativo sugli arresti anomali, che può favoriscono notevolmente il debug (vedi Esempio).

GWP-ASan è progettato per non incorrere in un overhead della CPU significativo. GWP-ASan introduce un piccolo overhead della RAM fisso quando è abilitato. Questo overhead viene stabilito il sistema Android e attualmente sono di circa 70 kibibyte (KiB) per ogni processo interessato.

Attiva la tua app

GWP-ASan può essere attivato dalle app a livello di singolo processo utilizzando Tag android:gwpAsanMode nel file manifest dell'app. Le seguenti opzioni sono supportati:

  • Sempre disattivata (android:gwpAsanMode="never"): impostazione completamente disattivata disattiva GWP-ASan nella tua app ed è l'impostazione predefinita per le app non di sistema.

  • Valore predefinito (android:gwpAsanMode="default" o non specificato): Android 13 (API) livello 33) e inferiore - GWP-ASan è disabilitato. Android 14 (livello API 34) e superiore: il GWP-ASan recuperabile è attivato.

  • Sempre attiva (android:gwpAsanMode="always"): questa impostazione consente di attivare GWP-ASan nella tua app, che include:

    1. Il sistema operativo riserva una quantità fissa di RAM per GWP-ASan operazioni, circa 70 KiB per ogni processo interessato. (Attiva GWP-ASan se la tua app non è particolarmente sensibile agli aumenti di memoria per l'utilizzo).

    2. GWP-ASan intercetta un sottoinsieme scelto casualmente di allocazioni dell'heap e li dispone in una regione speciale che rileva in modo affidabile la sicurezza della memoria violazioni delle norme.

    3. Quando si verifica una violazione della sicurezza della memoria nella regione speciale, GWP-ASan che interrompe il processo.

    4. GWP-ASan fornisce ulteriori informazioni sull'errore nell'arresto anomalo report.

Per attivare GWP-ASan a livello globale per la tua app, aggiungi quanto segue al tuo File AndroidManifest.xml:

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

Inoltre, GWP-ASan può essere abilitato o disabilitato esplicitamente per specifici dei vari processi secondari della tua app. Puoi scegliere come target attività e servizi utilizzando i processi per cui GWP-ASan è stato esplicitamente attivato o disattivato. Consulta quanto segue per una esempio:

<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>

GWP-ASan recuperabile

Android 14 (livello API 34) e versioni successive supportano GWP-ASan recuperabile, il che aiuta gli sviluppatori trovano bug heap-buffer-overflow e heap-use-after-free in la produzione senza compromettere l'esperienza utente. Quando il valore di android:gwpAsanMode è non specificato in un AndroidManifest.xml, l'app utilizza il recupero GWP-ASan

GWP-ASan recuperabile differisce dal GWP-ASan di base per i seguenti aspetti:

  1. GWP-ASan recuperabile è abilitato solo su circa l'1% dei lanci di app. piuttosto che a ogni lancio di applicazioni.
  2. Quando viene rilevato un bug heap-use-after-free o heap-buffer-overflow, questo bug compare nel report sugli arresti anomali (tombstone). Questo report sugli arresti anomali è disponibile tramite ActivityManager#getHistoricalProcessExitReasons , uguale all'originale GWP-ASan.
  3. Anziché uscire dopo aver eseguito il dump del report sugli arresti anomali, GWP-ASan recuperabile provoca il danneggiamento della memoria e l'app continua a essere eseguita. Anche se la procedura potrebbe continuare come al solito, il comportamento dell'app specificato. A causa del danneggiamento della memoria, l'app potrebbe arrestarsi in modo anomalo futuro o potrebbe continuare senza alcun impatto visibile agli utenti.
  4. GWP-ASan recuperabile viene disabilitato dopo il dump del report sugli arresti anomali. Pertanto, un'app può ricevere un solo report GWP-ASan recuperabile per lancio di app.
  5. Se nell'app è installato un gestore di segnali personalizzato, non viene mai chiamato un segnale SIGSEGV indicativo di un guasto GWP-ASan recuperabile.

Gli arresti anomali di GWP-ASan recuperabili indicano istanze reali di memoria il danneggiamento dei dispositivi degli utenti finali, consigliamo vivamente di valutare e correggere i bug identificati da GWP-ASan recuperabili con priorità elevata.

Assistenza per gli sviluppatori

Queste sezioni descrivono i problemi che potrebbero verificarsi quando si utilizza GWP-ASan e come risolvere il problema.

Tracce allocazione/deallocation mancanti

Se stai diagnosticando un arresto anomalo nativo che sembra mancare di allocazione/deallocation, è probabile che nella tua applicazione manchi puntatori dei frame. GWP-ASan utilizza i puntatori frame per registrare le tracce di allocazione e deallocation per per migliorare le prestazioni e non è in grado di annullare l'analisi dello stack presenti.

I puntatori frame sono attivi per impostazione predefinita per i dispositivi ARM64 e disattivati per impostazione predefinita per i dispositivi ARM32 dispositivi mobili. Poiché le applicazioni non hanno controllo su libc, in generale lo è non è possibile per GWP-ASan raccogliere tracce di allocazione/deallocation per i dati a 32 bit eseguibili o app. Le applicazioni a 64 bit devono garantire che non creato con -fomit-frame-pointer in modo che GWP-ASan possa raccogliere l'allocazione delle analisi dello stack di deallocation.

Riprodurre le violazioni della sicurezza

GWP-ASan è progettato per rilevare le violazioni di sicurezza della memoria heap sui dispositivi degli utenti. GWP-ASan fornisce tutto il contesto possibile sull'arresto anomalo (traccia di accesso la violazione, la stringa causa e le tracce di allocazione/deallocation), ma essere ancora difficile da capire come si sia verificata la violazione. Purtroppo, poiché il bug di rilevamento è probabilistico, i report GWP-ASan sono spesso difficili da riprodurre su dispositivo locale.

In questi casi, se il bug interessa dispositivi a 64 bit, devi usare HWAddressSanitizer (HWASan). HWASan rileva la sicurezza della memoria le violazioni in modo affidabile in stack, heap e globali. L'esecuzione dell'applicazione con HWASan potrebbe riprodurre in modo affidabile lo stesso risultato segnalato GWP-ASan

Nei casi in cui l'esecuzione dell'applicazione in HWASan non sia sufficiente per principale un bug, dovresti provare a fuzz il codice in questione. Puoi mirare ai tuoi tentativi di fuzzing in base alle informazioni contenute nei Report GWP-ASan, che può rilevare e rivelare in modo affidabile l'integrità del codice sottostante per risolvere problemi di produzione e facilità d'uso.

Esempio

Questo esempio di codice nativo presenta un bug use-after-free dell'heap:

#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));
}

Per un'esecuzione di test utilizzando il codice di esempio riportato sopra, GWP-ASan ha catturato utilizzo illegale e ha attivato il report sugli arresti anomali riportato di seguito. GWP-ASan ha automaticamente ha migliorato il report, fornendo informazioni sul tipo di arresto anomalo, metadati di allocazione e lo stack di allocazione e deallocation associato le tracce audio.

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
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)
      ...

Ulteriori informazioni

Per scoprire di più sui dettagli di implementazione di GWP-ASan, consulta la documentazione LLVM. Per ulteriori informazioni sui report sugli arresti anomali nativi di Android, consulta Diagnostica degli arresti anomali nativi.