Kernel AddressSanitizer

Al igual que los sanitizadores basados en LLVM para los componentes del espacio del usuario, Android incluye el Kernel AddressSanitizer (KASan). KASan es una combinación de modificaciones del kernel y del tiempo de compilación que dan como resultado un sistema instrumentado que permite un descubrimiento de errores y un análisis de causa raíz más sencillos.

KASan puede detectar muchos tipos de infracciones de memoria en el kernel. También puede detectar lecturas y escrituras fuera de límites en la pila, el montón y las variables globales, y puede detectar el uso después de la liberación y la doble liberación.

Al igual que ASan, KASan usa una combinación de instrumentación de funciones de memoria en tiempo de compilación y memoria sombra para hacer un seguimiento de los accesos a la memoria en tiempo de ejecución. En KASan, una octava parte del espacio de memoria del kernel se dedica a la memoria sombra, que determina si un acceso a la memoria es válido o no.

KASan es compatible con las arquitecturas x86_64 y arm64. Forma parte del kernel upstream desde la versión 4.0 y se portó a versiones anteriores de kernels basados en Android 3.18.

Además de KASan, kcov es otra modificación del kernel útil para las pruebas. kcov se desarrolló para permitir las pruebas de fuzz guiadas por cobertura en el kernel. Mide la cobertura en términos de entradas de llamadas al sistema y es útil con sistemas de fuzzing, como syzkaller.

Implementación

Para compilar un kernel con KASan y kcov habilitados, agrega las siguientes marcas de compilación a la configuración de compilación del kernel:

CONFIG_KASAN
CONFIG_KASAN_INLINE
CONFIG_TEST_KASAN
CONFIG_KCOV
CONFIG_SLUB
CONFIG_SLUB_DEBUG
CONFIG_CC_OPTIMIZE_FOR_SIZE

Y quita lo siguiente:

CONFIG_SLUB_DEBUG_ON
CONFIG_SLUB_DEBUG_PANIC_ON
CONFIG_KASAN_OUTLINE
CONFIG_KERNEL_LZ4

Luego, compila y escribe el kernel en la memoria flash como de costumbre. El kernel de KASan es considerablemente más grande que el original. Si es necesario, modifica los parámetros de arranque y la configuración del cargador de arranque para tener esto en cuenta.

Después de escribir el kernel en la memoria flash, revisa los registros de inicio del kernel para ver si KASan está habilitado y en ejecución. El kernel se inicia con información del mapa de memoria para KASan, como la siguiente:

...
[    0.000000] c0      0 Virtual kernel memory layout:
[    0.000000] c0      0     kasan   : 0xffffff8000000000 - 0xffffff9000000000   (    64 GB)
[    0.000000] c0      0     vmalloc : 0xffffff9000010000 - 0xffffffbdbfff0000   (   182 GB)
[    0.000000] c0      0     vmemmap : 0xffffffbdc0000000 - 0xffffffbfc0000000   (     8 GB maximum)
[    0.000000] c0      0               0xffffffbdc0000000 - 0xffffffbdc3f95400   (    63 MB actual)
[    0.000000] c0      0     PCI I/O : 0xffffffbffa000000 - 0xffffffbffb000000   (    16 MB)
[    0.000000] c0      0     fixed   : 0xffffffbffbdfd000 - 0xffffffbffbdff000   (     8 KB)
[    0.000000] c0      0     modules : 0xffffffbffc000000 - 0xffffffc000000000   (    64 MB)
[    0.000000] c0      0     memory  : 0xffffffc000000000 - 0xffffffc0fe550000   (  4069 MB)
[    0.000000] c0      0       .init : 0xffffffc001d33000 - 0xffffffc001dce000   (   620 KB)
[    0.000000] c0      0       .text : 0xffffffc000080000 - 0xffffffc001d32284   ( 29385 KB)
...

Así se ve un error:

[   18.539668] c3      1 ==================================================================
[   18.547662] c3      1 BUG: KASAN: null-ptr-deref on address 0000000000000008
[   18.554689] c3      1 Read of size 8 by task swapper/0/1
[   18.559988] c3      1 CPU: 3 PID: 1 Comm: swapper/0 Tainted: G        W      3.18.24-xxx #1
[   18.569275] c3      1 Hardware name: Android Device
[   18.577433] c3      1 Call trace:
[   18.580739] c3      1 [<ffffffc00008b32c>] dump_backtrace+0x0/0x2c4
[   18.586985] c3      1 [<ffffffc00008b600>] show_stack+0x10/0x1c
[   18.592889] c3      1 [<ffffffc001481194>] dump_stack+0x74/0xc8
[   18.598792] c3      1 [<ffffffc000202ee0>] kasan_report+0x11c/0x4d0
[   18.605038] c3      1 [<ffffffc00020286c>] __asan_load8+0x20/0x80
[   18.611115] c3      1 [<ffffffc000bdefe8>] android_verity_ctr+0x8cc/0x1024
[   18.617976] c3      1 [<ffffffc000bcaa2c>] dm_table_add_target+0x3dc/0x50c
[   18.624832] c3      1 [<ffffffc001bdbe60>] dm_run_setup+0x50c/0x678
[   18.631082] c3      1 [<ffffffc001bda8c0>] prepare_namespace+0x44/0x1ac
[   18.637676] c3      1 [<ffffffc001bda170>] kernel_init_freeable+0x328/0x364
[   18.644625] c3      1 [<ffffffc001478e20>] kernel_init+0x10/0xd8
[   18.650613] c3      1 ==================================================================

Además, si los módulos están habilitados en tu kernel, puedes cargar el módulo del kernel test_kasan para realizar más pruebas. El módulo intenta acceder a la memoria fuera de los límites y usarla después de liberarla, y es útil para garantizar que habilitaste correctamente KASan en un dispositivo de destino.