Operations 30 min read

Master Linux Memory Bugs with KASAN: From Fundamentals to Real‑World Debugging

This guide walks Linux developers and operators through the fundamentals of kernel memory management, common memory bugs, and step‑by‑step configuration and usage of KASAN—including shadow memory, compile‑time instrumentation, kernel build options, and practical code examples—to quickly locate and fix out‑of‑bounds, use‑after‑free, and leak issues.

Deepin Linux
Deepin Linux
Deepin Linux
Master Linux Memory Bugs with KASAN: From Fundamentals to Real‑World Debugging

1. Linux Memory Management Overview

Before diving into KASAN, understand the basics of Linux memory management. The kernel uses virtual memory to give each process an isolated address space and employs mechanisms such as the Buddy System for large allocations and the Slab allocator for small, frequently used objects. Proper allocation prevents leaks and fragmentation, which can otherwise degrade performance or cause crashes.

1.1 Common Memory Problems

Typical hidden memory bugs include:

Out‑of‑bounds access – accessing memory outside the allocated range, often via incorrect array indices, leading to data corruption or crashes.

Use‑after‑free – accessing memory after it has been released, which can overwrite other data or cause undefined behavior.

Memory leaks – forgetting to free dynamically allocated memory, gradually exhausting system RAM.

#include <stdio.h>
#include <string.h>

void demonstrate_memory_corruption() {
    int array[10] = {0};
    int important_data = 100;
    printf("=== Out‑of‑bounds example ===
");
    printf("initial important_data = %d
", important_data);
    // normal access
    array[5] = 10;
    printf("array[5] = %d (still OK)
", array[5]);
    // out‑of‑bounds access
    array[10] = 200; // corrupts important_data
    printf("important_data after OOB = %d
", important_data);
}

int main() { demonstrate_memory_corruption(); return 0; }

2. Meet KASAN – The Kernel Memory Detective

KASAN (Kernel Address Sanitizer) is the kernel‑space counterpart of the user‑space AddressSanitizer. It detects out‑of‑bounds accesses, use‑after‑free, and leaks by maintaining a shadow memory that mirrors real memory at a 1‑byte‑per‑8‑bytes ratio.

2.1 How KASAN Works

When a memory region is allocated, KASAN marks the corresponding shadow bytes as accessible (value 0). When the region is freed, the shadow bytes are marked as inaccessible (non‑zero). Every load or store checks the shadow byte; illegal accesses trigger an immediate error report with address, size, and stack trace.

2.2 Shadow Memory Details

The shadow memory acts like a health record for each memory byte. A zero value means the byte is safe; a non‑zero value indicates a problem such as freed memory or out‑of‑bounds region. KASAN reports the exact location and type of the fault.

#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE 10
unsigned char shadow_memory[ARRAY_SIZE/8 + 1] = {0};

void init_shadow() {
    for (int i = 0; i < 5; i++) shadow_memory[i] = 0x00; // accessible
    for (int i = 5; i < sizeof(shadow_memory); i++) shadow_memory[i] = 0xff; // inaccessible
}

int check_memory_access(void *ptr, size_t size) {
    size_t addr = (size_t)ptr;
    size_t base = (size_t)malloc(ARRAY_SIZE * sizeof(int));
    size_t offset = addr - base;
    size_t shadow_index = offset / 8;
    size_t shadow_bit   = offset % 8;
    if (shadow_index >= sizeof(shadow_memory)) return 0;
    if ((shadow_memory[shadow_index] & (1 << shadow_bit)) != 0) return 0;
    return 1;
}

int main() {
    int *arr = (int *)malloc(ARRAY_SIZE * sizeof(int));
    init_shadow();
    printf("=== KASAN demo ===
");
    if (check_memory_access(&arr[5], sizeof(int))) arr[5] = 10;
    if (check_memory_access(&arr[15], sizeof(int))) arr[15] = 20; else printf("illegal access!
");
    free(arr);
    return 0;
}

2.3 Kernel Integration

To enable KASAN, edit the kernel configuration (e.g., via make menuconfig) and enable:

Kernel hacking → Memory Debugging → KASAN: runtime memory debugger

Optionally enable inline instrumentation, extra info, HW tags, low‑overhead, or concurrent modes depending on performance needs.

After saving, rebuild the kernel ( make -j$(nproc)), install modules ( make modules_install) and the new kernel ( make install), then reboot into the KASAN‑enabled kernel.

2.4 Useful KASAN Config Options

CONFIG_KASAN_RECORD

– records allocation/free history for deeper debugging (higher overhead). CONFIG_KASAN_HW_TAGS – uses ARM64 MTE hardware tags for low‑overhead checks. CONFIG_KASAN_LOW_OVERHEAD – reduces runtime cost at the expense of some detection coverage. CONFIG_KASAN_CONCURRENT – improves detection in multithreaded environments.

3. KASAN in Practice – Real‑World Cases

3.1 Preparing a Kernel Module

Ensure CONFIG_HAVE_ARCH_KASAN and CONFIG_KASAN are set to ‘y’. Then write a module that intentionally triggers a bug.

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>

static int __init kasan_demo_init(void) {
    char *buf = kmalloc(10, GFP_KERNEL);
    if (!buf) return -ENOMEM;
    buf[11] = 'A'; // out‑of‑bounds
    kfree(buf);
    printk(KERN_INFO "module loaded
");
    return 0;
}
static void __exit kasan_demo_exit(void) { printk(KERN_INFO "module unloaded
"); }
module_init(kasan_demo_init);
module_exit(kasan_demo_exit);
MODULE_LICENSE("GPL");

When run on a KASAN‑enabled kernel, the following report appears:

==================================================================
BUG: KASAN: slab-out-of-bounds in kasan_demo_init+0x74/0x98 at addr ffffffff88888888
Write of size 1 by task ...
Call trace:
 ...
Object at ffffffff88888880, in cache kmalloc‑size …

The report pinpoints the exact line ( buf[11] = 'A';) and the offending address, allowing a quick fix (e.g., use buf[9] instead).

3.2 Use‑After‑Free Example

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>

static int __init use_after_free_init(void) {
    char *buf = kmalloc(10, GFP_KERNEL);
    if (!buf) return -ENOMEM;
    kfree(buf);
    buf[5] = 'B'; // use after free
    printk(KERN_INFO "module loaded
");
    return 0;
}
static void __exit use_after_free_exit(void) { printk(KERN_INFO "module unloaded
"); }
module_init(use_after_free_init);
module_exit(use_after_free_exit);
MODULE_LICENSE("GPL");

KASAN reports a “use‑after‑free” error with stack traces showing where the memory was freed and where it was accessed, guiding the developer to null‑out the pointer after kfree or avoid the access entirely.

3.3 Additional Tips

Always verify that KASAN is enabled in the running kernel ( cat /sys/kernel/debug/kasan/status). Use the extra‑info options for complex bugs, and consider low‑overhead mode for production systems where performance matters.

KernelLinuxC programmingMemory DebuggingKASANShadow Memory
Deepin Linux
Written by

Deepin Linux

Research areas: Windows & Linux platforms, C/C++ backend development, embedded systems and Linux kernel, etc.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.