DirecciónDesinfectante

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 fuentes third_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 correspondiente 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 /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 para SANITIZE_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.

Documentación de apoyo