Research into KASAN in SerenityOS

Introduction

Kernel Address Sanitizer (KASAN) is a dynamic analysis technology to find dynamic memory errors in OS Kernels. It's based on instrumentation injected by the compiler which checks all memory accesses made during execution.

I'm interested in enabling KASAN for SerenityOS

Links:

Here's the NetBSD presentation:

Lets start hacking!

So my first attempt at doing anything was to just throw in -fsanitize=kernel-address and see what falls out. Here's the first diff:

diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt
index 451060bf2..c7d9e5bec 100644
--- a/Kernel/CMakeLists.txt
+++ b/Kernel/CMakeLists.txt
@@ -268,6 +268,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pie -fPIE -fno-rtti -ffreestanding -fbu
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mno-80387 -mno-mmx -mno-sse -mno-sse2")
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-asynchronous-unwind-tables")
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector-strong")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=kernel-address")
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib -nostdinc -nostdinc++")

 add_link_options(LINKER:-T ${CMAKE_CURRENT_BINARY_DIR}/linker.ld -nostdlib)

We compile successfully with the new flag, but we fail to link. The linker complains about about a bunch of missing __asan_load{n}_noabort functions.

... snip ...
./Build/Kernel/././AK/OwnPtr.h:140: undefined reference to `__asan_load4_noabort'
./Build/Kernel/././AK/NonnullOwnPtr.h:124: undefined reference to `__asan_load4_noabort'
./Build/Kernel/././Kernel/VM/RangeAllocator.h:48: undefined reference to `__asan_load4_noabort'
./Build/Kernel/././AK/OwnPtr.h:116: undefined reference to `__asan_handle_no_return'
./Build/Kernel/././AK/NonnullOwnPtr.h:124: undefined reference to `__asan_load4_noabort'
./Build/Kernel/././Kernel/VM/RangeAllocator.h:48: undefined reference to `__asan_load4_noabort'
./Build/Kernel/././AK/NonnullOwnPtr.h:124: undefined reference to `__asan_load4_noabort'
./Build/Kernel/././Kernel/VM/RangeAllocator.h:49: undefined reference to `__asan_load4_noabort'

... snip ...

Looking at NetBSD's implementation of KASAN shows that they have common handler macros for these functions.

Excerpt from sys/kern/subr_asan.c:

#define ASAN_LOAD_STORE(size)                   \
    void __asan_load##size(unsigned long);          \
    void __asan_load##size(unsigned long addr)      \
    {                           \
        kasan_shadow_check(addr, size, false, __RET_ADDR);\
    }                           \
    void __asan_load##size##_noabort(unsigned long);    \
    void __asan_load##size##_noabort(unsigned long addr)    \
    {                           \
        kasan_shadow_check(addr, size, false, __RET_ADDR);\
    }                           \
    void __asan_store##size(unsigned long);         \
    void __asan_store##size(unsigned long addr)     \
    {                           \
        kasan_shadow_check(addr, size, true, __RET_ADDR);\
    }                           \
    void __asan_store##size##_noabort(unsigned long);   \
    void __asan_store##size##_noabort(unsigned long addr)   \
    {                           \
        kasan_shadow_check(addr, size, true, __RET_ADDR);   \
    }

I guess I'll need to stub out these symbols for serenity when I get time to work on this further.