+适度的内存开销允许在内存受限的设备上用真实的工作负载进行测试。
-基于软件标签的KASAN模式仅在Clang中受支持。
+基于硬件标签的KASAN或HW_TAGS KASAN,用CONFIG_KASAN_HW_TAGS启用,被
+用作现场内存错误检测器或作为安全缓解的模式。这种模式只在支持MTE(内存标签
+扩展)的arm64 CPU上工作,但它的内存和性能开销很低,因此可以在生产中使用。
-硬件KASAN模式(#3)依赖硬件来执行检查,但仍需要支持内存标签指令的编译器
-版本。GCC 10+和Clang 11+支持此模式。
+关于每种KASAN模式的内存和性能影响的细节,请参见相应的Kconfig选项的描述。
-两种软件KASAN模式都适用于SLUB和SLAB内存分配器,而基于硬件标签的KASAN目前
-仅支持SLUB。
+通用模式和基于软件标签的模式通常被称为软件模式。基于软件标签的模式和基于
+硬件标签的模式被称为基于标签的模式。
-目前x86_64、arm、arm64、xtensa、s390、riscv架构支持通用KASAN模式,仅
-arm64架构支持基于标签的KASAN模式。
+支持
+----
+
+体系架构
+~~~~~~~~
+
+在x86_64、arm、arm64、powerpc、riscv、s390和xtensa上支持通用KASAN,
+而基于标签的KASAN模式只在arm64上支持。
+
+编译器
+~~~~~~
+
+软件KASAN模式使用编译时工具在每个内存访问之前插入有效性检查,因此需要一个
+提供支持的编译器版本。基于硬件标签的模式依靠硬件来执行这些检查,但仍然需要
+一个支持内存标签指令的编译器版本。
+
+通用KASAN需要GCC 8.3.0版本或更高版本,或者内核支持的任何Clang版本。
+
+基于软件标签的KASAN需要GCC 11+或者内核支持的任何Clang版本。
+
+基于硬件标签的KASAN需要GCC 10+或Clang 12+。
+
+内存类型
+~~~~~~~~
+
+通用KASAN支持在所有的slab、page_alloc、vmap、vmalloc、堆栈和全局内存
+中查找错误。
+
+基于软件标签的KASAN支持slab、page_alloc、vmalloc和堆栈内存。
+
+基于硬件标签的KASAN支持slab、page_alloc和不可执行的vmalloc内存。
+
+对于slab,两种软件KASAN模式都支持SLUB和SLAB分配器,而基于硬件标签的
+KASAN只支持SLUB。
用法
----
@@ -53,7 +84,7 @@ arm64架构支持基于标签的KASAN模式。
对于软件模式,还可以在 ``CONFIG_KASAN_OUTLINE`` 和 ``CONFIG_KASAN_INLINE``
之间进行选择。outline和inline是编译器插桩类型。前者产生较小的二进制文件,
-而后者快1.1-2倍。
+而后者快2倍。
要将受影响的slab对象的alloc和free堆栈跟踪包含到报告中,请启用
``CONFIG_STACKTRACE`` 。要包括受影响物理页面的分配和释放堆栈跟踪的话,
@@ -172,21 +203,29 @@ KASAN受通用 ``panic_on_warn`` 命令行参数的影响。启用该功能后
默认情况下,KASAN只为第一次无效内存访问打印错误报告。使用 ``kasan_multi_shot`` ,
KASAN会针对每个无效访问打印报告。这有效地禁用了KASAN报告的 ``panic_on_warn`` 。
+另外,独立于 ``panic_on_warn`` , ``kasan.fault=`` 引导参数可以用来控制恐慌和报
+告行为:
+
+- ``kasan.fault=report`` 或 ``=panic`` 控制是只打印KASAN报告还是同时使内核恐慌
+ (默认: ``report`` )。即使启用了 ``kasan_multi_shot`` ,也会发生内核恐慌。
+
基于硬件标签的KASAN模式(请参阅下面有关各种模式的部分)旨在在生产中用作安全缓解
-措施。因此,它支持允许禁用KASAN或控制其功能的引导参数。
+措施。因此,它支持允许禁用KASAN或控制其功能的附加引导参数。
- ``kasan=off`` 或 ``=on`` 控制KASAN是否启用 (默认: ``on`` )。
-- ``kasan.mode=sync`` 或 ``=async`` 控制KASAN是否配置为同步或异步执行模式(默认:
- ``sync`` )。同步模式:当标签检查错误发生时,立即检测到错误访问。异步模式:
- 延迟错误访问检测。当标签检查错误发生时,信息存储在硬件中(在arm64的
+- ``kasan.mode=sync`` 、 ``=async`` 或 ``=asymm`` 控制KASAN是否配置
+ 为同步或异步执行模式(默认:``sync`` )。
+ 同步模式:当标签检查错误发生时,立即检测到错误访问。
+ 异步模式:延迟错误访问检测。当标签检查错误发生时,信息存储在硬件中(在arm64的
TFSR_EL1寄存器中)。内核会定期检查硬件,并且仅在这些检查期间报告标签错误。
+ 非对称模式:读取时同步检测不良访问,写入时异步检测。
+
+- ``kasan.vmalloc=off`` 或 ``=on`` 禁用或启用vmalloc分配的标记(默认:``on`` )。
- ``kasan.stacktrace=off`` 或 ``=on`` 禁用或启用alloc和free堆栈跟踪收集
(默认: ``on`` )。
-- ``kasan.fault=report`` 或 ``=panic`` 控制是只打印KASAN报告还是同时使内核恐慌
- (默认: ``report`` )。即使启用了 ``kasan_multi_shot`` ,也会发生内核恐慌。
实施细则
--------
@@ -244,7 +283,6 @@ KASAN会针对每个无效访问打印报告。这有效地禁用了KASAN报告
基于软件标签的KASAN使用0xFF作为匹配所有指针标签(不检查通过带有0xFF指针标签
的指针进行的访问)。值0xFE当前保留用于标记已释放的内存区域。
-基于软件标签的KASAN目前仅支持对Slab和page_alloc内存进行标记。
基于硬件标签的KASAN模式
~~~~~~~~~~~~~~~~~~~~~~~
@@ -262,8 +300,6 @@ KASAN会针对每个无效访问打印报告。这有效地禁用了KASAN报告
基于硬件标签的KASAN使用0xFF作为匹配所有指针标签(不检查通过带有0xFF指针标签的
指针进行的访问)。值0xFE当前保留用于标记已释放的内存区域。
-基于硬件标签的KASAN目前仅支持对Slab和page_alloc内存进行标记。
-
如果硬件不支持MTE(ARMv8.5之前),则不会启用基于硬件标签的KASAN。在这种情况下,
所有KASAN引导参数都将被忽略。
@@ -275,6 +311,8 @@ KASAN会针对每个无效访问打印报告。这有效地禁用了KASAN报告
影子内存
--------
+本节的内容只适用于软件KASAN模式。
+
内核将内存映射到地址空间的几个不同部分。内核虚拟地址的范围很大:没有足够的真实
内存来支持内核可以访问的每个地址的真实影子区域。因此,KASAN只为地址空间的某些
部分映射真实的影子。
@@ -297,7 +335,7 @@ CONFIG_KASAN_VMALLOC
~~~~~~~~~~~~~~~~~~~~
使用 ``CONFIG_KASAN_VMALLOC`` ,KASAN可以以更大的内存使用为代价覆盖vmalloc
-空间。目前,这在x86、riscv、s390和powerpc上受支持。
+空间。目前,这在arm64、x86、riscv、s390和powerpc上受支持。
这通过连接到vmalloc和vmap并动态分配真实的影子内存来支持映射。
@@ -349,10 +387,10 @@ KASAN连接到vmap基础架构以懒清理未使用的影子内存。
``kasan_disable_current()``/``kasan_enable_current()`` 部分注释这部分代码。
这也会禁用通过函数调用发生的间接访问的报告。
-对于基于标签的KASAN模式(包括硬件模式),要禁用访问检查,请使用
-``kasan_reset_tag()`` 或 ``page_kasan_tag_reset()`` 。请注意,通过
-``page_kasan_tag_reset()`` 临时禁用访问检查需要通过 ``page_kasan_tag``
-/ ``page_kasan_tag_set`` 保存和恢复每页KASAN标签。
+对于基于标签的KASAN模式,要禁用访问检查,请使用 ``kasan_reset_tag()`` 或
+``page_kasan_tag_reset()`` 。请注意,通过 ``page_kasan_tag_reset()``
+临时禁用访问检查需要通过 ``page_kasan_tag`` / ``page_kasan_tag_set`` 保
+存和恢复每页KASAN标签。
测试
~~~~
@@ -381,11 +419,10 @@ KASAN连接到vmap基础架构以懒清理未使用的影子内存。
当由于缺少KASAN报告而导致测试失败时::
- # kmalloc_double_kzfree: EXPECTATION FAILED at lib/test_kasan.c:629
- Expected kasan_data->report_expected == kasan_data->report_found, but
- kasan_data->report_expected == 1
- kasan_data->report_found == 0
- not ok 28 - kmalloc_double_kzfree
+ # kmalloc_double_kzfree: EXPECTATION FAILED at lib/test_kasan.c:974
+ KASAN failure expected in "kfree_sensitive(ptr)", but none occurred
+ not ok 44 - kmalloc_double_kzfree
+
最后打印所有KASAN测试的累积状态。成功::