AddressSanitizer (ASan) è uno strumento rapido basato sul compilatore per il rilevamento di bug di memoria nel codice nativo.
ASan rileva:
- overflow/underflow del buffer di stack e heap
- Utilizzo dell'heap dopo il rilascio
- 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. Ci sono solo 256 valori di tag possibili, quindi esiste una probabilità fissa dello 0,4% di perdere qualsiasi 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 quanto tempo fa è stata deallocata la memoria. Questo rende HWASan migliore di ASan. Puoi scoprire di più sul design di 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 creare ed eseguire parti/tutti i dispositivi Android con ASan. Se stai creando un'app SDK/NDK con ASan, consulta Address Sanitizer.
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
A causa del funzionamento di ASan, una libreria creata con ASan può essere utilizzata solo da un programma eseguibile creato con ASan.
Per pulire una libreria condivisa utilizzata in più eseguibili, non tutti
creati con ASan, sono necessarie due copie della libreria. 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 inserita in /system/lib/asan
anziché in
/system/lib
. Poi esegui l'eseguibile con:
LD_LIBRARY_PATH=/system/lib/asan
Per i demoni 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 dover 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'operazione di smontaggio rapida basata su puntatori frame per registrare una traccia stacchetta per ogni evento di allocazione e deallocazione della memoria nel programma. La maggior parte di Android è costruita senza puntatori 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
In alternativa, imposta ASAN_OPTIONS=fast_unwind_on_malloc=0
nell'ambiente
di processo. Quest'ultimo può usare molta 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 file binario
llvm-symbolizer
sia presente in/system/bin
.llvm-symbolizer
viene compilato dalle origini inthird_party/llvm/tools/llvm-symbolizer
. - Filtra il report tramite lo script
external/compiler-rt/lib/asan/scripts/symbolize.py
.
Il secondo approccio può fornire più dati (ovvero file:line
località) grazie alla disponibilità di librerie simbolizzate sull'host.
ASan nelle app
ASan non può vedere il codice Java, ma può rilevare bug nelle librerie JNI. Per farlo, devi creare l'eseguibile con ASan, che in
questo caso è /system/bin/app_process(32|64)
. In questo modo, ASan viene attivata contemporaneamente in tutte le app sul dispositivo, il che rappresenta un carico elevato, ma un dispositivo con 2 GB di RAM dovrebbe essere in grado di gestirlo.
Aggiungi LOCAL_SANITIZE:=address
alla regola di compilazione 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
seguenti righe al blocco di righe rientrate contenenti class main
, anche
inserito con rientro della stessa quantità:
setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib setenv ASAN_OPTIONS allow_user_segv_handler=true
Esegui la compilazione, la sincronizzazione ADB, il flash del boot di Fastboot e il riavvio.
Utilizzare la proprietà wrap
L'approccio nella sezione precedente inserisce ASan in ogni app del sistema (in realtà in ogni discendente del processo Zygote). È possibile eseguire una sola (o più) app con ASan, scambiando un po' di overhead di memoria per un avvio più lento delle app.
A questo scopo, 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 nella 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 si arresta in modo anomalo e il report viene stampato 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 comandi riportati di seguito nello stesso albero di build.
make -j42
SANITIZE_TARGET=address make -j42
In questa modalità, userdata.img
contiene librerie aggiuntive e deve essere anche eseguito il flashing 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 sovrascrive le directory degli oggetti intermedi quando il valore $SANITIZE_TARGET
è cambiato. In questo modo viene forzata una nuova build di tutti
i target, mantenendo i file binari installati in /system/lib
.
Alcuni target non possono essere creati con ASan:
- Eseguibili con link statico
LOCAL_CLANG:=false
targetLOCAL_SANITIZE:=false
non sono stati approvati perSANITIZE_TARGET=address
Eseguibili come questi vengono ignorati nella compilazione SANITIZE_TARGET
e la versione della prima chiamata a make viene lasciata in /system/bin
.
Le librerie come questa vengono create senza ASan. Possono contenere del codice ASan delle librerie statiche da cui dipendono.