AddressSanitizer (ASan) es una herramienta rápida basada en compilador para detectar errores de memoria en código nativo.
ASan detecta:
- Desbordamiento/desbordamiento insuficiente del búfer de pila y montón
- Uso del montón después de gratis
- Uso de pila fuera del alcance
- Doble gratis/libre salvaje
ASan se ejecuta en ARM de 32 y 64 bits, además de x86 y x86-64. La sobrecarga de la CPU de ASan es aproximadamente 2x, la sobrecarga del tamaño del código está entre 50% y 2x, y una gran sobrecarga de memoria (dependiendo de sus patrones de asignación, pero del orden de 2x).
Android 10 y la rama principal de AOSP en AArch64 admiten ASan acelerado por hardware (HWASan) , una herramienta similar con menor sobrecarga de RAM y una mayor variedad de errores detectados. HWASan detecta el uso de la pila después del retorno, además de los errores detectados por ASan.
HWASan tiene una sobrecarga de tamaño de código y CPU similar, pero una sobrecarga de RAM mucho menor (15%). HWASan no es determinista. Sólo hay 256 valores de etiquetas posibles, por lo que existe una probabilidad fija del 0,4% de pasar por alto algún error. HWASan no tiene las zonas rojas de tamaño limitado de ASan para detectar desbordamientos y la cuarentena de capacidad limitada para detectar uso después de la liberación, por lo que a HWASan no le importa qué tan grande es el desbordamiento o cuánto tiempo hace que se desasignó la memoria. Esto hace que HWASan sea mejor que ASan. Puedes leer más sobre el diseño de HWASan o sobre el uso de HWASan en Android .
ASan detecta desbordamientos de pila/globales además de desbordamientos de montón, y es rápido con una sobrecarga de memoria mínima.
Este documento describe cómo construir y ejecutar partes o todo Android con ASan. Si está creando una aplicación SDK/NDK con ASan, consulte Address Sanitizer en su lugar.
Desinfección de ejecutables individuales con ASan
Agregue LOCAL_SANITIZE:=address
o sanitize: { address: true }
a la regla de compilación para el ejecutable. Puede buscar en el código ejemplos existentes o encontrar otros desinfectantes disponibles.
Cuando se detecta un error, ASan imprime un informe detallado tanto en la salida estándar como en logcat
y luego bloquea el proceso.
Desinfección de bibliotecas compartidas con ASan
Debido a la forma en que funciona ASan, una biblioteca creada con ASan solo puede ser utilizada por un ejecutable creado con ASan.
Para desinfectar una biblioteca compartida que se utiliza en varios ejecutables, no todos creados con ASan, necesita dos copias de la biblioteca. La forma recomendada de hacer esto es agregar lo siguiente a Android.mk
para el módulo en cuestión:
LOCAL_SANITIZE:=address LOCAL_MODULE_RELATIVE_PATH := asan
Esto coloca la biblioteca en /system/lib/asan
en lugar de /system/lib
. Luego, ejecuta tu ejecutable con:
LD_LIBRARY_PATH=/system/lib/asan
Para demonios del sistema, agregue lo siguiente a la sección correspondiente de /init.rc
o /init.$device$.rc
.
setenv LD_LIBRARY_PATH /system/lib/asan
Verifique que el proceso esté utilizando bibliotecas de /system/lib/asan
cuando estén presentes leyendo /proc/$PID/maps
. Si no es así, es posible que deba desactivar 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.
Mejores seguimientos de pila
ASan utiliza un desenrollador rápido basado en punteros de fotogramas para registrar un seguimiento de la pila para cada evento de asignación y desasignación de memoria en el programa. La mayor parte de Android está construido sin punteros de marco. Como resultado, a menudo sólo se obtienen uno o dos fotogramas significativos. Para solucionar este problema, reconstruya la biblioteca con ASan (¡recomendado!) o con:
LOCAL_CFLAGS:=-fno-omit-frame-pointer LOCAL_ARM_MODE:=arm
O configure ASAN_OPTIONS=fast_unwind_on_malloc=0
en el entorno del proceso. Este último puede consumir mucho CPU, dependiendo de la carga.
Simbolización
Inicialmente, los informes ASan contienen referencias a compensaciones en binarios y bibliotecas compartidas. Hay dos formas de obtener información de línea y archivo fuente:
- Asegúrese de que el binario
llvm-symbolizer
esté presente en/system/bin
.llvm-symbolizer
se crea a partir de fuentesthird_party/llvm/tools/llvm-symbolizer
. - Filtre el informe a través del script
external/compiler-rt/lib/asan/scripts/symbolize.py
.
El segundo enfoque puede proporcionar más datos (es decir, ubicaciones file:line
) debido a la disponibilidad de bibliotecas simbolizadas en el host.
ASan en aplicaciones
ASan no puede ver el código Java, pero puede detectar errores en las bibliotecas JNI. Para eso, necesita compilar el ejecutable con ASan, que en este caso es /system/bin/app_process( 32|64 )
. Esto habilita ASan en todas las aplicaciones del dispositivo al mismo tiempo, lo cual es una carga pesada, pero un dispositivo con 2 GB de RAM debería poder manejar esto.
Agregue LOCAL_SANITIZE:=address
a la regla de compilación app_process
en frameworks/base/cmds/app_process
. Ignore el destino app_process__asan
en el mismo archivo por ahora (si todavía está allí en el momento de leer esto).
Edite la sección service zygote
del archivo system/core/rootdir/init.zygote( 32|64 ).rc
apropiado para agregar las siguientes líneas al bloque de líneas sangradas que contiene class main
, también sangrada en la misma cantidad:
setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib setenv ASAN_OPTIONS allow_user_segv_handler=true
Compilación, sincronización de adb, arranque flash fastboot y reinicio.
Usando la propiedad de envoltura
El enfoque de la sección anterior coloca ASan en cada aplicación del sistema (en realidad, en cada descendiente del proceso Zygote). Es posible ejecutar solo una (o varias) aplicaciones con ASan, intercambiando algo de memoria para un inicio más lento de la aplicación.
Esto se puede hacer iniciando su aplicación con el wrap.
propiedad. El siguiente ejemplo ejecuta la aplicación Gmail en ASan:
adb root
adb shell setenforce 0 # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"
En este contexto, asanwrapper
reescribe /system/bin/app_process
en /system/bin/asan/app_process
, que está construido con ASan. También agrega /system/lib/asan
al inicio de la ruta de búsqueda de biblioteca dinámica. De esta manera, se prefieren las bibliotecas instrumentadas con ASan de /system/lib/asan
a las bibliotecas normales en /system/lib
cuando se ejecutan con asanwrapper
.
Si se encuentra un error, la aplicación falla y el informe se imprime en el registro.
DESINFECTAR_TARGET
Android 7.0 y superiores incluyen soporte para construir toda la plataforma Android con ASan a la vez. (Si está creando una versión superior a Android 9, HWASan es una mejor opción).
Ejecute los siguientes comandos en el mismo árbol de compilación.
make -j42
SANITIZE_TARGET=address make -j42
En este modo, userdata.img
contiene bibliotecas adicionales y también debe actualizarse en el dispositivo. Utilice la siguiente línea de comando:
fastboot flash userdata && fastboot flashall
Esto crea dos conjuntos de bibliotecas compartidas: normal en /system/lib
(la primera invocación make) y ASan-instrumentada en /data/asan/lib
(la segunda invocación make). Los ejecutables de la segunda compilación sobrescriben los de la primera compilación. Los ejecutables instrumentados con ASan obtienen una ruta de búsqueda de biblioteca diferente que incluye /data/asan/lib
antes de /system/lib
mediante el uso de /system/bin/linker_asan
en PT_INTERP
.
El sistema de compilación bloquea los directorios de objetos intermedios cuando el valor $SANITIZE_TARGET
ha cambiado. Esto fuerza una reconstrucción de todos los objetivos mientras se preservan los archivos binarios instalados en /system/lib
.
Algunos objetivos no se pueden construir con ASan:
- Ejecutables vinculados estáticamente
-
LOCAL_CLANG:=false
-
LOCAL_SANITIZE:=false
no son ASan paraSANITIZE_TARGET=address
Los ejecutables como estos se omiten en la compilación SANITIZE_TARGET
y la versión de la primera invocación make se deja en /system/bin
.
Bibliotecas como esta se construyen sin ASan. Pueden contener código ASan de las bibliotecas estáticas de las que dependen.