IndirizzoSanitizer

AddressSanitizer (ASan) è uno strumento veloce basato su compilatore per rilevare bug di memoria nel codice nativo.

ASAN rileva:

  • Overflow/underflow del buffer dello stack e dell'heap
  • Uso dell'heap dopo gratuito
  • Uso dello stack al di fuori dell'ambito
  • Doppio libero/libero selvaggio

ASan funziona sia su ARM a 32 bit che a 64 bit, oltre a x86 e x86-64. L'overhead della CPU di ASan è di circa 2x, l'overhead della dimensione del codice è compreso tra 50% e 2x e un grande overhead di memoria (dipende dai modelli di allocazione, ma nell'ordine di 2x).

Android 10 e ramo principale AOSP sul sostegno AArch64 accelerazione hardware Asan (HWASan) , uno strumento simile con minori costi RAM e una grande gamma di insetti identificati. HWASan rileva l'utilizzo dello stack dopo il ritorno, oltre ai bug rilevati da ASan.

HWASan ha un sovraccarico di CPU e codice simile, ma un sovraccarico di RAM molto più piccolo (15%). HWASan è non deterministico. Ci sono solo 256 possibili valori di tag, quindi c'è 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 a capacità limitata per il rilevamento dell'uso dopo l'assenza, quindi non importa a HWASan quanto sia grande l'overflow o quanto tempo fa la memoria è stata deallocata. Questo rende HWASan migliore di ASan. Si può leggere di più sulla progettazione di HWASan o circa l'uso di HWASan su Android .

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

Questo documento descrive come creare ed eseguire parti/tutto di Android con ASan. Se si sta costruendo uno SDK / NDK app con Asan, vedere Indirizzo Sanitizer , invece.

Sanificazione dei singoli eseguibili con Asan

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

Quando viene rilevato un bug, Asan stampa un verbose riportano sia sullo standard output e logcat e quindi si blocca il processo.

Sanificazione delle librerie condivise con ASan

A causa del modo in cui funziona ASan, una libreria creata con ASan può essere utilizzata solo da un eseguibile creato con ASan.

Per disinfettare una libreria condivisa utilizzata in più eseguibili, non tutti creati con ASan, sono necessarie due copie della libreria. Il metodo raccomandato per farlo è quello di aggiungere quanto segue alla Android.mk per il modulo in questione:

LOCAL_SANITIZE:=address
LOCAL_MODULE_RELATIVE_PATH := asan

Questo mette la libreria in /system/lib/asan invece di /system/lib . Quindi, esegui il tuo eseguibile con:

LD_LIBRARY_PATH=/system/lib/asan

Per demoni di sistema, aggiungere la seguente alla sezione appropriata di /init.rc o /init.$device$.rc .

setenv LD_LIBRARY_PATH /system/lib/asan

Verificare che il processo sta utilizzando le librerie da /system/lib/asan quando presente da lettura /proc/$PID/maps . In caso contrario, potrebbe essere necessario disabilitare 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.

Migliori tracce dello stack

ASan utilizza uno svolgitore veloce basato su frame pointer per registrare una traccia dello stack per ogni allocazione di memoria e evento di deallocazione nel programma. La maggior parte di Android è costruita senza puntatori ai frame. Di conseguenza, spesso ottieni solo uno o due frame significativi. Per risolvere questo problema, ricostruisci la libreria con ASan (consigliato!) o con:

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

O impostare ASAN_OPTIONS=fast_unwind_on_malloc=0 in ambiente di processo. Quest'ultimo può essere molto impegnativo per la 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 il file di origine e le informazioni sulla riga:

  • Assicurarsi che il llvm-symbolizer binario è presente nel /system/bin . llvm-symbolizer è costruito da fonti in third_party/llvm/tools/llvm-symbolizer .
  • Filtrare il rapporto attraverso l' external/compiler-rt/lib/asan/scripts/symbolize.py script.

Il secondo approccio può fornire più dati (cioè, file:line posizioni) a causa della disponibilità di librerie simbolizzati sull'host.

Asan nelle app

ASan non può vedere nel codice Java, ma può rilevare bug nelle librerie JNI. Per questo, è necessario costruire l'eseguibile con Asan, che in questo caso è /system/bin/app_process( 32|64 ) . Ciò abilita Asan in tutte le app sul dispositivo contemporaneamente, il che è un carico pesante, ma un dispositivo con 2 GB di RAM dovrebbe essere in grado di gestirlo.

Aggiungere LOCAL_SANITIZE:=address al app_process regola build in frameworks/base/cmds/app_process . Ignorare il app_process__asan bersaglio nello stesso file, per ora (se è ancora lì al momento di leggere questo).

Modificare il service zygote sezione della appropriata system/core/rootdir/init.zygote( 32|64 ).rc file per aggiungere le seguenti righe al blocco di righe rientrate contenenti class main , rientrato anche della stessa quantità:

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

Crea, sincronizzazione adb, avvio flash fastboot e riavvio.

Usando 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 solo una (o più) app con ASan, scambiando un sovraccarico di memoria per un avvio più lento dell'app.

Questo può essere fatto avviando l'app con l' wrap. proprietà. L'esempio seguente esegue 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 riscritture /system/bin/app_process al /system/bin/asan/app_process , che è costruito con Asan. Si aggiunge anche /system/lib/asan all'inizio del percorso di ricerca della libreria dinamica. Questo modo librerie asan-strumentato da /system/lib/asan sono preferiti a librerie normali /system/lib durante l'esecuzione con asanwrapper .

Se viene rilevato un bug, l'app si arresta in modo anomalo e il rapporto viene stampato nel registro.

SANITIZE_TARGET

Android 7.0 e versioni successive includono il supporto per la creazione dell'intera piattaforma Android con ASan contemporaneamente. (Se stai creando una versione superiore 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 extra e deve essere balenato al dispositivo pure. Usa la seguente riga di comando:

fastboot flash userdata && fastboot flashall

Ciò crea due serie di librerie condivise: normale /system/lib (il primo marca invocazione), e Asan-strumentazione in /data/asan/lib (la seconda marca invocazione). Gli eseguibili della seconda build sovrascrivono quelli della prima build. Eseguibili asan-strumentati ottenere un diverso percorso di ricerca della libreria che comprende /data/asan/lib prima /system/lib attraverso l'utilizzo di /system/bin/linker_asan in PT_INTERP .

I clobbers sistema di compilazione directory oggetto intermedie quando il $SANITIZE_TARGET valore è cambiato. Questo forze una ricostruzione di tutti gli obiettivi, mantenendo i binari installati in /system/lib .

Alcuni target non possono essere costruiti con ASan:

  • Eseguibili collegati staticamente
  • LOCAL_CLANG:=false obiettivi
  • LOCAL_SANITIZE:=false non sono ASan'd per SANITIZE_TARGET=address

Eseguibili come questi vengono saltati nel SANITIZE_TARGET costruzione, e la versione dal primo make invocazione viene lasciato in /system/bin .

Le biblioteche come questa sono costruite senza Asan. Possono contenere del codice ASan dalle librerie statiche da cui dipendono.

Documentazione di supporto