AddressSanitizer

AddressSanitizer (ASan) è uno strumento rapido basato su compilatore per il rilevamento di memoria bug nel codice nativo.

ASan rileva:

  • Overflow/underflow del buffer dello stack e dell'heap
  • Utilizzo dell'heap dopo la prova senza costi
  • Utilizzo dello stack al di fuori dell'ambito
  • Doppio/libero/selvaggio

ASan funziona sia su ARM a 32 bit che a 64 bit, oltre che su x86 e x86-64. Il sovraccarico della CPU di ASan è di circa il doppio, il sovraccarico delle dimensioni del codice è compreso tra il 50% e il doppio e un notevole sovraccarico della memoria (a seconda dei pattern di allocazione, ma dell'ordine del doppio).

Android 10 e il ramo principale di AOSP su AArch64 supportano AddressSanitizer (HWASan) con assistenza hardware, uno strumento simile con un overhead della RAM inferiore e una gamma più ampia di bug rilevati. HWASan rileva l'utilizzo dello stack dopo il ritorno, oltre ai bug rilevati da ASan.

HWASan ha un overhead simile per CPU e dimensioni del codice, ma un overhead RAM molto più ridotto (15%). HWASan non è deterministico. Esistono solo 256 valori possibili per i tag, quindi esiste una probabilità fissa dello 0,4% di non rilevare eventuali bug. HWASan non ha le zone rosse di dimensioni limitate di ASan per il rilevamento degli overflow e la quarantena con capacità limitata per il rilevamento dell'uso dopo il rilascio, quindi per HWASan non ha importanza la dimensione dell'overflow o da quanto tempo la memoria è stata deallocata. Questo rende HWASan migliore di ASan. Puoi scoprire di più sulle dei contenuti HWASan o sull'utilizzo di HWASan su Android.

ASan rileva gli overflow di stack/globali oltre agli overflow dell'heap ed è veloce con un sovraccarico di memoria minimo.

Questo documento descrive come compilare ed eseguire parti/tutto Android con ASan. Se stai creando un'app SDK/NDK con ASan, consulta Disinfettante per indirizzi .

Sanitizza i singoli eseguibili con ASan

Aggiungi LOCAL_SANITIZE:=address o sanitize: { address: true } alla regola di compilazione per l'eseguibile. Puoi cercare nel codice esempi esistenti o trovare gli altri disinfettanti disponibili.

Quando viene rilevato un bug, ASan stampa un report dettagliato sia nell'output standard sia in logcat e poi arresta in modo anomalo il processo.

Pulisci le librerie condivise con ASan

Per via del suo funzionamento, una libreria creata con ASan può essere utilizzata solo creato con ASan.

Per pulire una libreria condivisa utilizzata in più eseguibili, non tutti create con ASan, sono necessarie due copie della libreria. La il modo consigliato per farlo è aggiungere quanto segue a Android.mk per il modulo in questione:

LOCAL_SANITIZE:=address
LOCAL_MODULE_RELATIVE_PATH := asan

In questo modo la libreria viene posizionata in /system/lib/asan anziché /system/lib. Poi esegui l'eseguibile con:

LD_LIBRARY_PATH=/system/lib/asan

Per i daemon di sistema, aggiungi quanto segue alla sezione appropriata di /init.rc o /init.$device$.rc.

setenv LD_LIBRARY_PATH /system/lib/asan

Verifica che il processo utilizzi le librerie di /system/lib/asan se presenti leggendo /proc/$PID/maps. In caso contrario, potresti aver bisogno per disattivare SELinux:

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.

Analisi dello stack migliori

ASan utilizza un unwinder veloce basato su frame pointer per registrare uno stack per ogni evento di allocazione della memoria e di dealcazione nel programma. Più alta di Android è realizzato senza i cursori dei frame. Di conseguenza, spesso vengono generati solo uno o due frame significativi. Per risolvere il problema, ricrea la libreria con ASan (consigliato!) o con:

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

Oppure imposta ASAN_OPTIONS=fast_unwind_on_malloc=0 durante la procedura completamente gestito di Google Cloud. Quest'ultimo può richiedere molto tempo della CPU, a seconda del carico.

Simbolizzazione

Inizialmente, i report ASan contengono riferimenti agli offset nei file binari e nelle librerie condivise. Esistono due modi per ottenere informazioni sulla riga e sul file di origine:

  • Assicurati che il programma binario llvm-symbolizer sia presente in /system/bin. llvm-symbolizer viene creato da origini in third_party/llvm/tools/llvm-symbolizer.
  • Filtra il report tramite lo external/compiler-rt/lib/asan/scripts/symbolize.py script.

Il secondo approccio può fornire più dati (ossia file:line località) grazie la disponibilità di librerie simboliche sull'host.

ASan nelle app

ASan non può vedere il codice Java, ma può rilevare i bug nella JNI librerie. Per farlo, devi creare l'eseguibile con ASan, che questo caso è /system/bin/app_process(32|64). Questo attiva ASan in tutte le app sul dispositivo contemporaneamente, ma con 2 GB di RAM.

Aggiungi LOCAL_SANITIZE:=address a la regola di build app_process in frameworks/base/cmds/app_process. Per il momento, ignora il target app_process__asan nello stesso file (se è ancora presente al momento in cui leggi queste istruzioni).

Modifica la sezione service zygote del file system/core/rootdir/init.zygote(32|64).rc appropriato per aggiungere le righe seguenti al blocco di righe rientrate contenente class main, anche rientrato dello stesso valore:

    setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib
    setenv ASAN_OPTIONS allow_user_segv_handler=true

Creazione, sincronizzazione adb, avvio flash fastboot e riavvio.

Utilizzare la proprietà wrap

L'approccio nella sezione precedente inserisce ASan in ogni app nel sistema (in realtà, in ogni discendente della ). È possibile eseguire solo una (o più) app con ASan, scambiando un carico di memoria per un avvio più lento dell'app.

Per farlo, avvia l'app con la proprietà wrap.. Nell'esempio seguente viene eseguita l'app Gmail in ASan:

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

In questo contesto, asanwrapper riscriverà /system/bin/app_process in /system/bin/asan/app_process, che è creato con ASan. Inoltre, aggiunge /system/lib/asan all'inizio del percorso di ricerca della libreria dinamica. In questo modo, le librerie instrumentate con ASan di /system/lib/asan sono preferite alle normali librerie di /system/lib quando vengono eseguite con asanwrapper.

Se viene rilevato un bug, l'app ha un arresto anomalo e la segnalazione viene stampata su nel log.

SANITIZE_TARGET

Android 7.0 e versioni successive includono il supporto per la compilazione dell'intera piattaforma Android con ASan contemporaneamente. Se stai creando una release successiva ad Android 9, HWASan è una scelta migliore.

Esegui i seguenti comandi nello stesso albero di build.

make -j42
SANITIZE_TARGET=address make -j42

In questa modalità, userdata.img contiene librerie aggiuntive e deve essere sul dispositivo. Utilizza la seguente riga di comando:

fastboot flash userdata && fastboot flashall

Vengono creati due insiemi di librerie condivise: normali in/system/lib (la prima chiamata a make) e con strumenti ASan in/data/asan/lib (la seconda chiamata a make). I file eseguibili della seconda build sovrascrivono quelli della prima. Gli eseguibili con strumenti ASan hanno un percorso di ricerca della libreria diverso che include /data/asan/lib prima di /system/lib tramite l'utilizzo di /system/bin/linker_asan in PT_INTERP.

Il sistema di compilazione clona le directory degli oggetti intermedi quando Il valore di $SANITIZE_TARGET è stato modificato. Questa operazione forza la ricostruzione di tutti sceglie come target mantenendo i file binari installati in /system/lib.

Alcuni target non possono essere creati con ASan:

  • Eseguibili collegati in modo statico
  • LOCAL_CLANG:=false target
  • LOCAL_SANITIZE:=false non sono stati approvati per SANITIZE_TARGET=address

Gli eseguibili come questi vengono ignorati nella build SANITIZE_TARGET e versione della prima chiamata di make viene lasciata in /system/bin.

Librerie come questa vengono create senza ASan. Possono contenere alcuni ASan il codice dalle librerie statiche da cui dipendono.

Documentazione di supporto