L'NDK di Android supporta il disinfettante per indirizzi (noto anche come ASan) che inizia con il livello API 27 (Android O MR 1).
ASan è uno strumento basato su compilatore rapido per il rilevamento di bug di memoria nel codice nativo. ASan rileva:
- overflow e heap del buffer/overflow
- Utilizzo dell'heap dopo il giorno
- Utilizzo dello stack al di fuori dell'ambito
- Doppia libera/selvatta
L'overhead della CPU di ASan è circa 2 volte, il sovraccarico della dimensione del codice è compreso tra il 50% e il 2x e l'overhead della memoria è grande (a seconda dei pattern di allocazione, ma dell'ordine di 2x).
App di esempio
Un'app di esempio mostra come configurare una variante di build per Asan.
Build
Per creare il codice nativo (JNI) dell'app con il disinfettante per indirizzi, segui questi passaggi:
build-ndk
Nel file Application.mk:
APP_STL := c++_shared # Or system, or none.
APP_CFLAGS := -fsanitize=address -fno-omit-frame-pointer
APP_LDFLAGS := -fsanitize=address
Per ciascun modulo nel tuo file Android.mk:
LOCAL_ARM_MODE := arm
C-Make
Nel file build.gradle del tuo modulo:
android {
defaultConfig {
externalNativeBuild {
cmake {
// Can also use system or none as ANDROID_STL.
arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_STL=c++_shared"
}
}
}
}
Per ogni destinazione nel tuo file CMakeLists.txt:
target_compile_options(${TARGET} PUBLIC -fsanitize=address -fno-omit-frame-pointer)
set_target_properties(${TARGET} PROPERTIES LINK_FLAGS -fsanitize=address)
Esegui
A partire da Android O MR1 (livello API 27), un'applicazione può fornire uno script shell avvolgente che può includere o sostituire il processo dell'applicazione. Ciò consente a un'applicazione di cui è possibile eseguire il debug di personalizzare l'avvio dell'applicazione, il che consente di utilizzare ASan sui dispositivi di produzione.
- Aggiungi
android:debuggable
al manifest dell'applicazione. - Imposta
useLegacyPackaging
sutrue
nel filebuild.gradle
della tua app. Per ulteriori informazioni, consulta la guida dello script shell wrapper. - Aggiungi la libreria di runtime ASan a
jniLibs
del modulo dell'app. Aggiungi
wrap.sh
file con i seguenti contenuti a ogni directory nella directorysrc/main/resources/lib
.#!/system/bin/sh HERE="$(cd "$(dirname "$0")" && pwd)" export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1 ASAN_LIB=$(ls $HERE/libclang_rt.asan-*-android.so) if [ -f "$HERE/libc++_shared.so" ]; then # Workaround for https://github.com/android-ndk/ndk/issues/988. export LD_PRELOAD="$ASAN_LIB $HERE/libc++_shared.so" else export LD_PRELOAD="$ASAN_LIB" fi "$@"
Supponendo che il modulo dell'applicazione del progetto sia denominato app
, la struttura di directory finale deve includere quanto segue:
<project root>
└── app
└── src
└── main
├── jniLibs
│ ├── arm64-v8a
│ │ └── libclang_rt.asan-aarch64-android.so
│ ├── armeabi-v7a
│ │ └── libclang_rt.asan-arm-android.so
│ ├── x86
│ │ └── libclang_rt.asan-i686-android.so
│ └── x86_64
│ └── libclang_rt.asan-x86_64-android.so
└── resources
└── lib
├── arm64-v8a
│ └── wrap.sh
├── armeabi-v7a
│ └── wrap.sh
├── x86
│ └── wrap.sh
└── x86_64
└── wrap.sh
Analisi dello stack
Il Disinfettante indirizzo deve annullare lo stack di ogni chiamata malloc
/realloc
/free
. Le opzioni disponibili sono due:
Uno strumento di scorrimento basato sul puntatore del frame "rapido". Viene utilizzato seguendo le istruzioni riportate nella sezione relativa alla creazione.
Un meccanismo di trasformazione CFI "lento". In questa modalità, ASan utilizza
_Unwind_Backtrace
. Richiede solo-funwind-tables
, che in genere è abilitata per impostazione predefinita.
La velocità di sblocco è l'impostazione predefinita per Malloc/realloc/free. L'opzione Slowwinder è l'impostazione predefinita per le analisi dello stack irreversibile. Lo sblocco lento può essere abilitato per tutte le tracce dello stack aggiungendo fast_unwind_on_malloc=0
alla variabile ASAN_OPTIONS
nel tuo wrap.sh.