How KASAN Detects Kernel Memory Errors: Shadow Memory, Redzones, and Log Analysis
This article explains the inner workings of KernelAddressSanitizer (KASAN) in the Linux kernel, covering how to enable it, the shadow‑memory mechanism, redzone handling for heap, global and stack allocations, and how to interpret the detailed KASAN bug reports generated at runtime.
1. Introduction
KASAN (KernelAddressSanitizer) is a dynamic memory‑error detector for the Linux kernel. It can catch out‑of‑bounds accesses, use‑after‑free, and other memory corruptions by instrumenting every memory access and checking a corresponding shadow memory.
2. Enabling KASAN
To use KASAN you must enable the kernel configuration options:
CONFIG_SLUB_DEBUG=y
CONFIG_KASAN=ySLUB_DEBUG used to be required because early KASAN depended on it; recent kernels no longer need the dependency, but keeping it on provides richer diagnostics.
3. Detection Mechanism – Shadow Memory
KASAN reserves one‑eighth of the address space as shadow memory . For each 8‑byte aligned region of real memory there is one byte in shadow memory that encodes the accessibility of the bytes:
Value 0 – all 8 bytes are valid.
Value 1..7 – the first N bytes are valid, the rest are poisoned.
Negative value – the whole 8‑byte region is invalid.
During compilation the compiler inserts calls to __asan_loadN or __asan_storeN before each memory access, where N is the access size.
4. How Checks Are Performed
For an 8‑byte access the generated code computes the shadow address as (addr >> 3) + KASAN_SHADOW_OFFSET and checks whether *shadow == 0. If the value is non‑zero, a bug is reported.
For smaller accesses (1, 2, or 4 bytes) the check is adjusted:
if (*shadow && *shadow < ((addr & 7) + N))
report_bug();Here N is the access size. The expression ensures that the access does not cross the poisoned boundary.
4.1 Allocation – Buddy System and SLUB
When the buddy allocator reserves pages, KASAN fills the corresponding shadow memory with 0 (all bytes accessible). When pages are freed, the shadow bytes are set to 0xFF, turning the region into a use‑after‑free detection zone.
SLUB objects receive a redzone after the usable part. For example, an object allocated with kmalloc(20) from the kmalloc‑32 cache occupies 32 bytes; the first 20 bytes are marked as accessible (shadow value 20), and the remaining 12 bytes are poisoned with 0xFC (redzone).
4.2 Global Variables
The compiler generates a constructor function named _GLOBAL__sub_I_<file>_<var> for each global variable. This function calls __asan_register_globals() with a struct kasan_global describing the variable’s address, size, redzone size, name, and source location.
struct kasan_global {
const void *beg; // start address
size_t size; // original size
size_t size_with_redzone; // rounded to 32‑byte alignment
const void *name; // variable name string
const void *module_name; // source file path
unsigned long has_dynamic_init;
const struct kasan_source_location *location;
};During early kernel boot the do_ctors() routine walks the __ctors_start … __ctors_end range and invokes all such constructors, thereby initializing the shadow memory for globals.
4.3 Stack Variables
For stack allocations the compiler also adds redzones. A typical function compiled with KASAN contains a hidden buffer before the real variable (e.g., rz1[32]) and after it (e.g., rz2[56]). The compiler writes the appropriate shadow values before the function runs and clears them on exit.
5. KASAN Bug Report Format
A typical KASAN log contains:
Bug type (e.g., "out of bounds access").
Faulting address and size of the offending operation.
Process and CPU information.
Call trace showing the kernel functions involved.
Object information (cache name, object address, redzone contents).
Memory state around the buggy address, displaying shadow bytes.
Example excerpt (truncated for brevity):
BUG: AddressSanitizer: out of bounds access in kmalloc_oob_right+0x65/0x75
Write of size 1 by task modprobe/1689
Object ffff8800693bc558: 6b6b6b6b... (SLUB object)
Shadow bytes around ffff8800693bc5d3: 00 00 00 00 00 00 00 00 03 fc fc ...
^The shadow byte 03 indicates that only the first three bytes of the 8‑byte chunk are valid, confirming an out‑of‑bounds write at offset 123.
6. Minimal Reproducible Module
The article provides a tiny kernel module that deliberately writes past the allocated size to trigger KASAN:
static void __init kmalloc_oob_right(void)
{
char *ptr;
size_t size = 123;
ptr = kmalloc(size, GFP_KERNEL);
if (!ptr) {
pr_err("Allocation failed
");
return;
}
ptr[size] = 'x'; // out‑of‑bounds write
kfree(ptr);
}
module_init(kmalloc_oob_right);
MODULE_LICENSE("GPL");Running this module on a kernel built with KASAN produces the detailed log described in section 5, allowing developers to verify the detection pipeline.
7. Conclusions
KASAN provides a fast, compile‑time‑instrumented way to catch memory errors in the kernel. By mapping real memory to shadow memory, inserting runtime checks, and poisoning freed regions, it can pinpoint the exact location, size, and call stack of a bug. The generated reports are rich enough to reconstruct the offending code path, but interpreting them requires understanding of shadow‑memory values, redzone layout, and the kernel’s allocation subsystems.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
