/**
- @file memory-trampling.md
- @page runtime_mem_trampling 内存越界检测(KASan / ASan)
- @ingroup system_debug_tools_runtime
- @brief 运行时内存访问越界检测机制,用于在程序执行过程中“即时发现”越界读写、UAF 等内存错误,尽可能在内存被进一步破坏之前暴露根因。
- @tableofcontents
- @section mem_trampling_overview 1. 概述
- 内存访问越界是嵌入式系统中最隐蔽、最难复现、也最容易导致系统崩溃的问题之一。它往往不会在越界发生的瞬间触发崩溃,
- 而是以“静默破坏”的形式污染其他任务或关键结构体,最终表现为随机 HardFault、结构体字段异常、链表断裂等难定位现象。
- 因此,在调试阶段启用运行时内存越界检测工具(KASan/ASan 系列)具有极高价值:强调“即时发现”,力求在错误首次发生时直接暴露问题根因。
- OpenVela 提供:
-
- 三类内核态 KASan 实现:Generic / SoftTag / MTE(Hardware Tagged)
-
- 一类仅用于模拟器环境的 ASan(Host-Side)
- @section mem_trampling_matrix 2. 能力范围对比(错误类型 / 精度 / 适用范围)
- 为帮助理解各机制的覆盖能力,下表总结了四种方案能够检测的错误类型与适用范围:
- @code{.text}
- 错误类型 / 特性 | Generic KASAN | SoftTag KASAN | MTE KASAN | ASAN(SIM Host)
- -------------------------------|--------------|---------------|----------|-----------------
- 堆越界写(Heap OOB Write) | ✓ | ✓ | ✓ | ✓
- 堆越界读(Heap OOB Read) | ✓ | ✓ | ✓ | ✓
- Use-After-Free(UAF) | ✓ | ✓ | ✓ | ✓
- Double Free / Invalid Free | ✓ | ✓ | ✓ | ✓
- 全局变量越界 | ✓ | ✓ | ✗ | ✓
- 栈变量越界 | ✗ | ✗ | ✗ | ✓
- 野指针/未初始化指针访问 | ✗(部分可检) | ✓ | ✓ | ✓
- 检测粒度/精度 | 4B(32位) / 8B(64位) | 4B(32位) / 8B(64位) | 16B | 16B 对齐
- 适用范围 | 通用 | 仅 ARM64(TBI) | 仅 ARM64 + MTE | 仅 SIM 模拟器
- @endcode
- @section mem_trampling_generic 3.2.1 Generic KASan(最通用实现)
- @subsection mem_trampling_generic_cfg 基本配置
- @code{.cfg}
- CONFIG_MM_KASAN_GENERIC=y
-
开启全局插桩
- CONFIG_MM_KASAN_INSTRUMENT_ALL=y
- @endcode
- @subsection mem_trampling_generic_principle 实现原理
- Generic KASan 是最通用、覆盖范围最广的内存访问越界检测方案。它通过编译器插桩,在每一次内存访问发生之前对访问地址进行合法性校验,
- 从而在内存被破坏的第一时间捕获非法访问行为。该方案不依赖指针标签或硬件支持,而是通过独立维护的 Shadow Memory(影子内存)记录真实内存的访问权限状态。
- @par i) 编译器插桩(-fsanitize=kernel-address)
- 开启
-fsanitize=kernel-address后,编译器会在每一次内存访问操作前插入检查调用。 - 例如,读写指针不会直接执行,而会被重写为类似:
- @code{.c}
- _asan_load1_noabort(addr);
- @endcode
- 检查函数通常会:
-
- 查询目标地址对应的 Shadow 条目(Shadow Value)
-
- 判定该地址是否位于合法访问区域
-
- 若 Shadow 标记为 “poisoned”,则报告为越界访问
- @par ii) Shadow Memory(影子内存映射)
- Shadow Memory 可理解为“主内存访问权限地图”:
-
- 通常 1 字节 Shadow 对应 8 字节真实内存(粒度因此常为 8B/64位 或 4B/32位)
-
- 插桩检查通过查询 Shadow 状态判断访问是否允许
- @par iii) Redzone Poisoning(红区标记)
- 在 malloc/free 等分配释放路径中,KASan 会在堆块前后插入不可访问区(Redzone),并在 Shadow 中标记为 poisoned:
-
- 用户缓冲区外的任意访问都会命中红区
-
- 越界读写将立即触发 KASan 报错
-
- 可捕获大多数堆溢出问题
- @par 报错示例(信息含义)
- 典型日志形态可能类似:
- @code{.text}
- kasan_report: kasan detected a read access error, address at 0xXXXXXXXX, size is 4, return address: 0xYYYYYYYY
- @endcode
- 表示在执行返回地址 0xYYYYYYYY 对应代码时,读取了一个非法/未分配的地址 0xXXXXXXXX。
- @section mem_trampling_softtag 3.2.2 SoftTag KASan(ARM64 软件指针标记模式)
- @subsection mem_trampling_softtag_cfg 基本配置
- @code{.cfg}
- CONFIG_MM_KASAN_SW_TAGS=y
-
开启全局插桩
- CONFIG_MM_KASAN_INSTRUMENT_ALL=y
- @endcode
- @subsection mem_trampling_softtag_principle 实现原理
- SoftTag KASan 是 KASan 在 ARM64 平台上的一种优化实现。
- 与 Generic KASan 使用 Shadow Memory 记录“访问权限”不同,SoftTag 通过 “指针 Tag” 与 “内存 Tag” 的匹配关系来判断访问是否合法,
- 依赖 ARM64 的 Top-Byte-Ignore(TBI)能力,将 Tag 放入指针的高 8 位。
- @subsection mem_trampling_softtag_vs_generic SoftTag 与 Generic 的关键差异
- @par ① 技术基础不同
-
- Generic:依赖 Shadow Memory(权限地图)
-
- SoftTag:依赖 ARM64 TBI(指针高字节 Tag)
- @par ② 检测机制不同
-
- Generic:访问前查询 Shadow bit/byte 是否 poisoned
-
- SoftTag:为每个分配块生成 Tag,同时写入:
-
- Pointer Tag(指针高 8 位)
-
- Memory Tag(对应的影子 Tag 区域)
- 访问时插桩逻辑比较 Pointer Tag 与 Memory Tag,一致则合法,不一致则非法
- @par ③ Redzone 处理方式不同
-
- Generic:依赖 Redzone + Shadow Poisoning
-
- SoftTag:不依赖 Redzone,主要通过 Tag 不匹配捕获越界
- @par ④ 限制
-
- 仅适用于 ARM64 架构(TBI)
- @section mem_trampling_mte 3.2.3 Hardware Tagged KASan(ARMv8.5 MTE 硬件模式)
- @subsection mem_trampling_mte_cfg 基本配置
- @code{.cfg}
- CONFIG_MM_KASAN_HW_TAGS=y
- @endcode
- @subsection mem_trampling_mte_principle 实现原理
- MTE KASan 同样基于 “Tag 匹配” 思想,但与 SoftTag 的“软件维护 + 插桩比对”不同,它依赖 ARMv8.5 MTE 硬件能力:
-
- Pointer Tag:仍存于指针高 8 位
-
- Memory Tag:由硬件 Tag 存储单元维护
- 在实际访存路径上,每一条 load/store 指令都会由硬件自动完成 Pointer Tag 与 Memory Tag 的匹配;
- 一旦校验失败,直接触发异常。该机制不依赖软件维护影子结构,也不依赖编译器是否插桩。
- @subsection mem_trampling_mte_vs_softtag SoftTag 与 MTE 的差异要点
-
- Tag 存储位置:
-
- SoftTag:Memory Tag 由软件维护在影子 Tag 区域
-
- MTE:Memory Tag 由硬件维护
-
- 检测触发位置:
-
- SoftTag:依赖插桩代码显式读取并比较 Tag(覆盖范围受插桩影响)
-
- MTE:硬件访存路径自动校验(覆盖所有真实读写:C/汇编/未插桩库)
-
- 性能影响:
-
- SoftTag:额外插桩指令 + 影子 Tag 访问与软件比较,开销较高,偏调试/验证
-
- MTE:访存指令本身几乎不增加额外指令,最接近“常态运行”,但前提是硬件平台具备 MTE 支持
- @section mem_trampling_asan 3.2.4 ASan(仅 SIM:Host-Side)
- @subsection mem_trampling_asan_cfg 基本配置
- @code{.cfg}
- CONFIG_SIM_ASAN=y
- @endcode
- @subsection mem_trampling_asan_notes 说明
- 在 OpenVela 中,CONFIG_SIM_ASAN 用于在 SIM 模拟环境下启用主机侧 ASan 检测,
- 作用是辅助开发者在仿真环境中提前发现内存越界问题。
- 由于 ASan 检测逻辑运行在 Host(主机)侧,并不参与 OpenVela 内核的运行时机制,
- 因此它不属于“真实硬件上的内核内存访问越界检查能力”。
- 若目标是在真实硬件上运行的越界检测,请使用 KASan 系列(Generic / SoftTag / MTE)。
- @section mem_trampling_reco 4. 实践建议(怎么选)
-
- 通用平台、优先覆盖面:@b Generic KASan
-
- ARM64 且希望降低 Shadow 维护成本:@b SoftTag KASan(但仍依赖插桩)
-
- ARM64 且硬件支持 MTE、希望接近常态运行:@b MTE KASan
-
- 仅在 SIM 仿真阶段提前暴露问题:@b Host-Side ASan
*/