Al igual que los validadores basados en LLVM para componentes de espacio de usuario, Android incluye el validador de direcciones del kernel (KASan). KASan es una combinación de modificaciones del kernel y del tiempo de compilación que da como resultado un sistema instrumentado que permite un descubrimiento de errores y un análisis de causa raíz más simples.
KASan puede detectar muchos tipos de violaciones de memoria en el kernel. También puede detectar lecturas y escrituras fuera de límite en la pila, el montón y las variables globales, y puede detectar el uso después de la liberación y la liberación doble.
Al igual que ASan, KASan usa una combinación de instrumentación de funciones de memoria en el tiempo de compilación y memoria en sombra para hacer un seguimiento de los accesos a la memoria durante el tiempo de ejecución. En KASan, un octavo del espacio de memoria del kernel está dedicado a la memoria en 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 kernels basados en Android 3.18.
Además de KASan, kcov es otra modificación del kernel que es útil para las pruebas. kcov se desarrolló para permitir pruebas de fuzz guiadas por la 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 en la memoria flash el kernel como de costumbre. El kernel de KASan es considerablemente más grande que el original. Si es necesario, modifica los parámetros de inicio y la configuración del bootloader para tener esto en cuenta.
Después de actualizar el kernel, verifica los registros de inicio del kernel para ver si KASan está habilitado y en ejecución. El kernel se iniciará 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 verá 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 realizar accesos fuera de los límites de la memoria y el uso después de la liberación, y es útil para garantizar que habilitaste correctamente KASan en un dispositivo de destino.