内存管理-77-内存检测工具-1-KMSAN-1-简介
注: Linux-6.1.114 默认不使能。
一、KMSAN 简介
CONFIG_KMSAN(Kernel Memory Sanitizer)检测内核中对未初始化内存的使用——即读取了从未被写入过的变量/内存区域。
1. 检测什么问题
/* 问题 1:栈变量未初始化 */ int do_something(void) { int result; //未赋值! if (result > 0) //KMSAN 报错:使用了未初始化的 result do_work(); return result; //KMSAN 报错 } /* 问题 2:kmalloc 后未初始化就使用 */ void *buf = kmalloc(128, GFP_KERNEL); //没有 memset 或赋值 if (buf[0] == 0x5A) //KMSAN 报错:读取未初始化的堆内存 ... /* 问题 3:向用户态泄漏未初始化数据(信息泄露漏洞) */ struct my_info info; info.field_a = 1; //info.field_b 未赋值(可能含有上一次的内核栈数据) copy_to_user(user_buf, &info, sizeof(info)); //KMSAN 报错:field_b 未初始化
第 3 种是最严重的安全问题——内核栈上的残留数据可能包含地址、密钥等敏感信息,未初始化就传给用户态就是信息泄漏漏洞(多个 CVE 由此产生)。
2. 工作原理
KMSAN 通过 编译器插桩 + shadow memory 追踪每个字节的初始化状态:
实际内存 Shadow Memory(KMSAN 维护) ┌─────--───────┐ ┌─────────-----------───┐ │ 0x41 (已写) │ │ 0x00 (已初始化) │ │ 0x?? (未写) │ │ 0xFF (未初始化) │ <-- 1:1 对应 │ 0x00 (已写) │ │ 0x00 (已初始化) │ └──────--──────┘ └─────────-----------───┘ 每个内存字节都有对应的 shadow byte: 0x00 = 已初始化(安全) 非零 = 未初始化(使用时报错)
3. 编译器做了什么
Clang 的 -fsanitize=kernel-memory 标志让编译器在每次:
(1) 内存写入时 → 将对应 shadow 标记为"已初始化"
(2) 内存读取时 → 检查 shadow,如果"未初始化"且值被用于分支/输出 → 报错
4. 内核运行时做了什么
(1) 页面分配时(alloc_pages)→ shadow 全部标记为"未初始化"
(2) 页面释放时(kmsan_free_page)→ shadow 标记为"未初始化"
(3) kmalloc 时 → shadow 标记为"未初始化"
(4) memset/memcpy 时 → 更新 shadow 状态
(5) copy_to_user 时 → 检查源数据的 shadow,有未初始化字节则报告
5. 与 KASAN 的区别
------------------------------------------------------------------------------------------------ 特性 KASAN KMSAN ------------------------------------------------------------------------------------------------ 检测目标 越界访问、use-after-free 使用未初始化内存 检测方式 shadow memory 标记可访问性 shadow memory 标记初始化状态 典型错误 buffer overflow、double-free 信息泄漏、未初始化变量 性能开销 ~2-3x ~3-5x 内存开销 +12.5%(1/8 shadow) +300%(shadow + origin tracking) 编译器支持 GCC / Clang 仅 Clang 内核版本 4.0+ 6.1+(较新) 架构支持 x86_64, arm64 仅 x86_64(6.1 中) ------------------------------------------------------------------------------------------------
6. 报错示例
===================================================== BUG: KMSAN: uninit-value in do_ioctl+0x234/0x560 Uninit was created at: kmalloc+0x12c/0x1e0 my_driver_open+0x48/0x120 CPU: 2 PID: 1234 Comm: test_app Call trace: do_ioctl+0x234/0x560 vfs_ioctl+0x44/0x60 __arm64_sys_ioctl+0xac/0xe0 ... Bytes 8-11 of 64 are uninitialized Memory access of size 4 at ffff888012345678 =====================================================
报告中会告诉你:
(1) 哪里使用了未初始化内存(do_ioctl+0x234)
(2) 这块内存是在哪里分配的(kmalloc in my_driver_open)
(3) 具体哪几个字节未初始化(bytes 8-11)
kmsan_free_page 在 free_pages_prepare 中的作用:
//free_pages_prepare 中: trace_mm_page_free(page, order); kmsan_free_page(page, order); //这里 void kmsan_free_page(struct page *page, unsigned int order) { /* * 将这个页面对应的 shadow memory 全部标记为"未初始化", 这样如果有人 use-after-free 读这个页面,KMSAN 会捕获到 *(即使物理内容还在,shadow 已经标记为 uninit) */ kmsan_internal_poison_memory(page_address(page), PAGE_SIZE << order, GFP_KERNEL, KMSAN_POISON_FREE); }
7. 开启方式
CONFIG_KMSAN=y # 需要 # - Clang 14+ 编译器 # - x86_64 架构(6.1 中仅支持 x86_64,后续版本可能支持 arm64) # - 不能与 KASAN 同时开启
8. 局限性
------------------------------------------------------------------------------------------- 局限 说明 ------------------------------------------------------------------------------------------- 仅 Clang GCC 不支持 -fsanitize=kernel-memory 仅 x86_64(6.1) ARM64 支持在后续内核版本中逐步添加 性能开销大 3-5 倍减速 + 大量额外内存(shadow + origin) 不能与 KASAN 共存 两者都用 shadow memory,实现有冲突 #### 误报 某些故意使用未初始化内存的场景(如随机数种子收集)需要手动标注 -------------------------------------------------------------------------------------------
ARM64 设备上不能用, Linux-6.1 的 KMSAN 仅支持 x86_64。如果需要检测未初始化内存问题,替代方案:
(1) CONFIG_INIT_STACK_ALL_ZERO=y:强制所有栈变量初始化为 0(消除问题而非检测), 实测默认6.1内核使能。
(2) CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y:所有页面/slab 分配时自动清零, 实测默认6.1内核使能。
9. 说Arm64目前不能用的依据
//Kconfig.kmsan config KMSAN bool "KMSAN: detector of uninitialized values use" depends on HAVE_ARCH_KMSAN && HAVE_KMSAN_COMPILER ...
arch/arm64/Kconfig 中没有 select HAVE_ARCH_KMSAN 或任何与 HAVE_ARCH_KMSAN 相关的内容,意味着 ARM64 在这个内核版本中不满足 KMSAN 的依赖条件,无法开启。
结合 mainline Linux 6.1 的公开信息(kernelnewbies.org 的 6.1 Release Notes 以及 Google KMSAN 项目的文档),KMSAN 在 6.1 合入主线时仅对 x86_64 实现了架构支持代码(shadow memory 映射、汇编桩等)。ARM64 的 KMSAN 支持在更后续的版本中才开始开发。
posted on 2026-08-21 14:57 Hello-World3 阅读(2) 评论(0) 收藏 举报
浙公网安备 33010602011771号