Kernel Address Sanitizer (KASan)

Ähnlich wie die LLVM-basierten Sanitizer für Userspace-Komponenten enthält Android den Kernel Address Sanitizer (KASAN). KASAN ist eine Kombination aus Kernel- und Kompilierzeitmodifikationen, die zu einem instrumentierten System führen, das eine einfachere Fehlererkennung und Ursachenanalyse ermöglicht.

KASAN kann viele Arten von Speicherverletzungen im Kernel erkennen. Es kann auch Out-of-Bound-Lese- und Schreibvorgänge auf Stack-, Heap- und globalen Variablen erkennen und kann Use-After-Free- und Double-Frees erkennen.

Ähnlich wie ASAN verwendet KASAN eine Kombination aus Speicherfunktionsinstrumentierung zur Kompilierungszeit und Schattenspeicher, um Speicherzugriffe zur Laufzeit zu verfolgen. In KASAN ist ein Achtel des Kernel-Speicherplatzes dem Schattenspeicher gewidmet, der bestimmt, ob ein Speicherzugriff gültig ist oder nicht.

KASAN wird auf x86_64- und arm64-Architekturen unterstützt. Es ist seit 4.0 Teil des Upstream-Kernels und wurde auf Android 3.18-basierte Kernel zurückportiert.

Neben KASAN ist kcov eine weitere Kernel-Modifikation, die zum Testen nützlich ist. kcov wurde entwickelt, um Coverage-gesteuerte Fuzz-Tests im Kernel zu ermöglichen. Es misst die Abdeckung in Bezug auf Systemaufrufeingaben und ist bei Fuzzing-Systemen wie Syzkaller nützlich.

Implementierung

Um einen Kernel mit aktiviertem KASAN und kcov zu kompilieren, fügen Sie die folgenden Build-Flags zu Ihrer Kernel-Build-Konfiguration hinzu:

CONFIG_KASAN
CONFIG_KASAN_INLINE
CONFIG_TEST_KASAN
CONFIG_KCOV
CONFIG_SLUB
CONFIG_SLUB_DEBUG
CONFIG_CC_OPTIMIZE_FOR_SIZE

Und Folgendes entfernen:

CONFIG_SLUB_DEBUG_ON
CONFIG_SLUB_DEBUG_PANIC_ON
CONFIG_KASAN_OUTLINE
CONFIG_KERNEL_LZ4

Anschließend erstellen und flashen Sie Ihren Kernel wie gewohnt. Der KASAN-Kernel ist deutlich größer als das Original. Ändern Sie bei Bedarf alle Boot-Parameter und Bootloader-Einstellungen, um dies zu berücksichtigen.

Überprüfen Sie nach dem Flashen des Kernels die Kernel-Boot-Protokolle, um festzustellen, ob KASAN aktiviert ist und ausgeführt wird. Der Kernel startet mit Speicherzuordnungsinformationen für KASAN, wie zum Beispiel:

...
[    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)
...

Und so sieht ein Bug aus:

[   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 ==================================================================

Wenn in Ihrem Kernel Module aktiviert sind, können Sie außerdem das Kernelmodul test_kasan für weitere Tests laden. Das Modul versucht, außerhalb der Grenzen auf den Speicher zuzugreifen und es nach dem Freigeben zu verwenden. Es ist nützlich, um sicherzustellen, dass Sie KASan auf einem Zielgerät korrekt aktiviert haben.