IndirizzoSanitizer

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

ASan rileva:

  • Overflow/underflow del buffer di stack e heap
  • Utilizzo dell'heap dopo la disponibilità
  • Lo stack utilizza l'ambito esterno
  • Doppia libera/selvaggia libera

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

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

HWASan ha un sovraccarico della CPU e delle dimensioni del codice simile, ma un sovraccarico della RAM molto inferiore (15%). HWASan non è deterministico. Ci sono solo 256 possibili valori di tag, quindi c'è una probabilità piatta dello 0,4% di perdere qualche bug. HWASan non dispone delle zone rosse di dimensioni limitate di ASan per il rilevamento di overflow e di una quarantena a capacità limitata per il rilevamento di use-after-free, quindi non importa a HWASan quanto è grande l'overflow o quanto tempo fa la memoria è stata deallocata. Ciò rende HWASan migliore di ASan. Puoi leggere ulteriori informazioni sulla progettazione di HWASan o sull'utilizzo di HWASan su Android .

ASan rileva gli overflow dello stack/globali 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 stai creando un'app SDK/NDK con ASan, vedi invece Address Sanitizer .

Sanificazione dei 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 rapporto dettagliato sia sullo standard output che su logcat e quindi 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 modo consigliato per farlo è aggiungere quanto segue ad Android.mk per il modulo in questione:

LOCAL_SANITIZE:=address
LOCAL_MODULE_RELATIVE_PATH := asan

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

LD_LIBRARY_PATH=/system/lib/asan

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

setenv LD_LIBRARY_PATH /system/lib/asan

Verificare che il processo stia utilizzando le librerie da /system/lib/asan quando presenti leggendo /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.

Meglio impilare le tracce

ASan utilizza uno svolgitore veloce basato su frame-pointer per registrare una traccia dello stack per ogni evento di allocazione e deallocazione della memoria nel programma. La maggior parte di Android è costruita senza puntatori ai frame. Di conseguenza, spesso si ottengono solo uno o due fotogrammi significativi. Per risolvere questo problema, ricostruisci 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 nell'ambiente del processo. Quest'ultimo può richiedere un notevole consumo di 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 sul file sorgente e sulla riga:

  • Assicurarsi che il file binario llvm-symbolizer sia presente in /system/bin . llvm-symbolizer è creato da sorgenti in third_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 posizioni file:line ) 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 questo, è necessario creare l'eseguibile con ASan, che in questo caso è /system/bin/app_process( 32|64 ) . Ciò abilita ASan in tutte le app del 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 alla regola di compilazione app_process in frameworks/base/cmds/app_process . Ignora la destinazione app_process__asan nello stesso file per ora (se è ancora lì nel momento in cui leggi questo).

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 contenente class main , anch'essa rientrata della stessa quantità:

    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.

Utilizzando 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 po' di sovraccarico di memoria per un avvio dell'app più lento.

Questo può essere fatto avviando la tua app con il 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 riscrive /system/bin/app_process in /system/bin/asan/app_process , che è creato con ASan. Aggiunge inoltre /system/lib/asan all'inizio del percorso di ricerca della libreria dinamica. In questo modo le librerie con strumenti ASan da /system/lib/asan sono preferite alle normali librerie in /system/lib quando vengono eseguite 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 simultanea dell'intera piattaforma Android con ASan. (Se stai creando una versione 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 anch'esso flashato sul dispositivo. Utilizzare la seguente riga di comando:

fastboot flash userdata && fastboot flashall

Questo crea due set di librerie condivise: normal in /system/lib (la prima invocazione make) e ASan-instrumented in /data/asan/lib (la seconda invocazione make). Gli eseguibili della seconda build sovrascrivono quelli della prima build. Gli eseguibili con strumenti ASan ottengono un percorso di ricerca della libreria diverso che include /data/asan/lib prima /system/lib attraverso l'uso di /system/bin/linker_asan in PT_INTERP .

Il sistema di compilazione blocca le directory degli oggetti intermedi quando il valore $SANITIZE_TARGET è cambiato. Ciò forza una ricostruzione di tutte le destinazioni preservando i binari installati in /system/lib .

Alcuni obiettivi non possono essere costruiti con ASan:

  • Eseguibili collegati staticamente
  • LOCAL_CLANG:=false bersagli
  • LOCAL_SANITIZE:=false non hanno ASan per SANITIZE_TARGET=address

Eseguibili come questi vengono saltati nella build SANITIZE_TARGET e la versione della prima invocazione di make viene lasciata in /system/bin .

Biblioteche come questa sono costruite senza ASan. Possono contenere codice ASan dalle librerie statiche da cui dipendono.

Documentazione di supporto