土法炼钢兴趣小组的算法知识备份

【操作系统百科】内核内存调试

文章导航

分类入口
os
标签入口
#kasan#kfence#kmemleak#slub-debug#ubsan

目录

用户态有 ASan/MSan/Valgrind;内核也有对等工具。KASAN 检测 UAF/OOB,KFENCE 在生产里低开销采样,kmemleak 抓泄漏。

一、先看图

flowchart TD
    BUG[内核内存 bug] --> TYPE{类型}
    TYPE -->|UAF/OOB| KASAN[KASAN<br/>shadow memory]
    TYPE -->|UAF/OOB 生产| KFENCE[KFENCE<br/>guard page 采样]
    TYPE -->|leak| KMEMLEAK[kmemleak<br/>GC 扫描]
    TYPE -->|corruption| SLUB[SLUB_DEBUG<br/>redzone/poison]
    KASAN --> REPORT[KASAN report<br/>stack trace]
    KFENCE --> REPORT2[KFENCE report]
    KMEMLEAK --> REPORT3[泄漏列表<br/>alloc stack]
    SLUB --> REPORT4[BUG: SLUB<br/>对象损坏]
    classDef detect fill:#388bfd22,stroke:#388bfd,color:#adbac7;
    classDef report fill:#f0883e22,stroke:#f0883e,color:#adbac7;
    class KASAN,KFENCE,KMEMLEAK,SLUB detect
    class REPORT,REPORT2,REPORT3,REPORT4 report

二、KASAN

2.1 Generic KASAN

基于 shadow memory:每 8 字节实际内存对应 1 字节 shadow(1/8 开销)。编译器在每次内存访问前插入 shadow 检查。

启用:CONFIG_KASAN=y CONFIG_KASAN_GENERIC=y

性能开销 ~2-3x CPU + ~1/8 内存。

2.2 SW Tag KASAN(arm64)

利用 TBI(Top Byte Ignore)在指针高 8 位存 tag,内存也标 tag。访问时比较——不匹配 = bug。

开销更低(~1.5-2x)但不如 generic 精确。

2.3 HW Tag KASAN(arm64 MTE)

利用 MTE 硬件做 tag 比较——几乎零 CPU 开销(~3-5%)。

CONFIG_KASAN_HW_TAGS=y,Pixel 8+ 已 dogfood。

2.4 KASAN report

BUG: KASAN: slab-use-after-free in func+0x42/0x80
Read of size 4 at addr ffff888012345678 by task myapp/1234

Allocated by task 1234:
 kmem_cache_alloc+0x...
 my_alloc_func+0x...

Freed by task 1234:
 kfree+0x...
 my_free_func+0x...

包含分配和释放的调用栈——直接定位 bug。

三、KFENCE(Kernel Electric Fence)

3.1 思路

KASAN 开销太大不能跑生产。KFENCE 用统计采样:每隔一段时间(默认 100ms),把一个 slab 分配重定向到 guard page pool。

[guard page] [object] [guard page]
     ↑                    ↑
   不可访问             不可访问

OOB → 碰到 guard page → 页错误 → report。UAF → 释放后 guard page 仍在 → 再次访问 report。

3.2 特点

启用:CONFIG_KFENCE=y,默认已开(6.x 多数发行版)。

cat /sys/kernel/debug/kfence/stats
# enabled: 1
# objects: 255
# sample_interval: 100

四、kmemleak

4.1 思路

定期(默认 10 分钟)扫描所有内核内存,查找”无引用”的分配——类似保守式 GC。

4.2 启用

CONFIG_DEBUG_KMEMLEAK=y
echo scan > /sys/kernel/debug/kmemleak       # 手动扫描
cat /sys/kernel/debug/kmemleak                # 查看泄漏
echo clear > /sys/kernel/debug/kmemleak       # 清除记录

4.3 报告

unreferenced object 0xffff8880... (size 128):
  comm "myapp", pid 1234, jiffies 4294967296
  backtrace:
    kmalloc+0x...
    my_driver_probe+0x...

4.4 局限

五、SLUB_DEBUG

E-42 提过。这里补充与其他工具的互补:

工具 检测 生产 开销
KASAN generic UAF/OOB/全覆盖 2-3x
KASAN HW tag UAF/OOB ✅ (arm64 MTE) 3-5%
KFENCE UAF/OOB/采样 <1%
SLUB_DEBUG corruption/double free 2-10x
kmemleak leak 10-20%

六、UBSAN / KCSAN

6.1 UBSAN

Undefined Behavior Sanitizer 的内核版:检测整数溢出、空指针解引用、对齐错误。

CONFIG_UBSAN=y
CONFIG_UBSAN_TRAP=y    # 触发时 BUG() 而非只打日志

6.2 KCSAN

Kernel Concurrency Sanitizer:检测 data race(并发读写同一变量无同步)。

CONFIG_KCSAN=y

报告示例:

BUG: KCSAN: data-race in func_a / func_b
  write to 0xffff... of 4 bytes by task A
  read to 0xffff... of 4 bytes by task B

修复:加锁、或标记 data_race() / READ_ONCE() / WRITE_ONCE()

七、实践工作流

7.1 开发/CI

CONFIG_KASAN=y
CONFIG_KFENCE=y
CONFIG_KMEMLEAK=y
CONFIG_UBSAN=y
CONFIG_KCSAN=y
CONFIG_SLUB_DEBUG=y

跑 syzkaller / LTP → 收集 report。

7.2 生产

CONFIG_KFENCE=y          # 低开销采样
CONFIG_KASAN_HW_TAGS=y   # arm64 MTE 有条件开

其余不开。KFENCE report 通过 dmesg / syslog 收集。

八、常见问题

A:KASAN 太慢 generic 模式确实 2-3x。arm64 有 MTE 可降到 3-5%。x86 只能用 KFENCE 替代。

B:kmemleak 误报多 清除后再 scan。排除 known false positive。

C:SLUB_DEBUG 生产不敢开slub_debug=FZP,task_struct 只对特定 cache。

九、小结


参考文献

工具


上一篇per-CPU 变量 下一篇用户态分配器

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-05-03 · os

【操作系统百科】Slab/SLUB 分配器

buddy 只管页粒度(4K+),内核大多数对象只有几十到几百字节。slab/SLUB 在 buddy 之上做对象级缓存。本文讲 slab 历史、SLUB 接手、SLOB 退场、kmem_cache、per-CPU cache、KASAN 集成。

2026-04-27 · os

【操作系统百科】内存回收

Linux 内存回收是 VM 最复杂的子系统之一。本文讲 active/inactive LRU、kswapd 与 direct reclaim、watermark 三线、swappiness 的真实含义、MGLRU 改造、memcg 回收与 PSI。

2026-04-28 · os

【操作系统百科】交换

swap 还值得开吗?本文讲 swap area 基础、swap cache、zram 压缩内存、zswap 前端压缩池、swappiness 的真实含义、容器里的 swap 策略,以及为什么现代 Android 全靠 zram 不靠磁盘。


By .