1 .. SPDX-License-Identifier: GPL-2.0 2 3 .. include:: ../disclaimer-zh_CN.rst 4 5 :Original: Documentation/dev-tools/kasan.rst 6 :Translator: 万家兵 Wan Jiabing <wanjiabing@ 7 8 内核地址消毒剂(KASAN) 9 ===================== 10 11 概述 12 ---- 13 14 Kernel Address SANitizer(KASAN)是一种动态 15 检查内存越界访问和使用已释放内 16 17 KASAN有三种模式: 18 19 1. 通用KASAN 20 2. 基于软件标签的KASAN 21 3. 基于硬件标签的KASAN 22 23 用CONFIG_KASAN_GENERIC启用的通用KASAN, 24 间的ASan。这种模式在许多CPU架构上 25 26 基于软件标签的KASAN或SW_TAGS KASAN, 27 可以用于调试和自我测试,类似于 28 适度的内存开销允许在内存受限的 29 30 基于硬件标签的KASAN或HW_TAGS KASAN, 31 用作现场内存错误检测器或作为安 32 扩展)的arm64 CPU上工作,但它的内 33 34 关于每种KASAN模式的内存和性能影 35 36 通用模式和基于软件标签的模式通 37 硬件标签的模式被称为基于标签的 38 39 支持 40 ---- 41 42 体系架构 43 ~~~~~~~~ 44 45 在x86_64、arm、arm64、powerpc、riscv、s3 46 而基于标签的KASAN模式只在arm64上支 47 48 编译器 49 ~~~~~~ 50 51 软件KASAN模式使用编译时工具在每 52 提供支持的编译器版本。基于硬件 53 一个支持内存标签指令的编译器版 54 55 通用KASAN需要GCC 8.3.0版本或更高版 56 57 基于软件标签的KASAN需要GCC 11+或者 58 59 基于硬件标签的KASAN需要GCC 10+或Clan 60 61 内存类型 62 ~~~~~~~~ 63 64 通用KASAN支持在所有的slab、page_alloc 65 中查找错误。 66 67 基于软件标签的KASAN支持slab、page_al 68 69 基于硬件标签的KASAN支持slab、page_al 70 71 对于slab,两种软件KASAN模式都支持S 72 KASAN只支持SLUB。 73 74 用法 75 ---- 76 77 要启用KASAN,请使用以下命令配置 78 79 CONFIG_KASAN=y 80 81 同时在 ``CONFIG_KASAN_GENERIC`` (启用通 82 (启用基于硬件标签的KASAN模式),和 83 的KASAN模式)之间进行选择。 84 85 对于软件模式,还可以在 ``CONFIG_KAS 86 之间进行选择。outline和inline是编译 87 而后者快2倍。 88 89 要将受影响的slab对象的alloc和free堆 90 ``CONFIG_STACKTRACE`` 。要包括受影响物 91 请启用 ``CONFIG_PAGE_OWNER`` 并使用 ``pa 92 93 启动参数 94 ~~~~~~~~ 95 96 KASAN受到通用 ``panic_on_warn`` 命令行 97 在打印出错误报告后会使内核恐慌 98 99 默认情况下,KASAN只对第一个无效 100 ``kasan_multi_shot``,KASAN对每一个无效 101 了KASAN报告的 ``panic_on_warn``。 102 103 另外,独立于 ``panic_on_warn`` 、 ``kas 104 来控制恐慌和报告行为。 105 106 - ``kasan.fault=report`` 或 ``=panic`` 控制 107 同时使内核恐慌(默认: ``report`` 108 启用,恐慌也会发生。 109 110 基于软件和硬件标签的KASAN模式( 111 踪收集行为: 112 113 - ``kasan.stacktrace=off`` 或 ``=on`` 禁用 114 迹的收集(默认: ``on`` )。 115 116 - ``kasan.stack_ring_size=<number of entries>` 117 目数(默认: ``32768`` )。 118 119 基于硬件标签的KASAN模式是为了在 120 支持额外的启动参数,允许完全禁 121 122 - ``kasan=off`` 或 ``=on`` 控制KASAN是否 123 124 - ``kasan.mode=sync``, ``=async`` or ``=asymm` 125 被配置为同步、异步或非对称的 126 同步模式:当标签检查异常发生 127 异步模式:不良访问的检测是延 128 件中(对于arm64来说是在TFSR_EL1寄 129 且只在这些检查中报告标签异常 130 非对称模式:读取时同步检测不 131 132 - ``kasan.vmalloc=off`` or ``=on`` 禁用或 133 134 错误报告 135 ~~~~~~~~ 136 137 典型的KASAN报告如下所示:: 138 139 ========================================== 140 BUG: KASAN: slab-out-of-bounds in kmalloc_ 141 Write of size 1 at addr ffff8801f44ec37b b 142 143 CPU: 1 PID: 2760 Comm: insmod Not tainted 144 Hardware name: QEMU Standard PC (i440FX + 145 Call Trace: 146 dump_stack+0x94/0xd8 147 print_address_description+0x73/0x280 148 kasan_report+0x144/0x187 149 __asan_report_store1_noabort+0x17/0x20 150 kmalloc_oob_right+0xa8/0xbc [kasan_test] 151 kmalloc_tests_init+0x16/0x700 [kasan_test 152 do_one_initcall+0xa5/0x3ae 153 do_init_module+0x1b6/0x547 154 load_module+0x75df/0x8070 155 __do_sys_init_module+0x1c6/0x200 156 __x64_sys_init_module+0x6e/0xb0 157 do_syscall_64+0x9f/0x2c0 158 entry_SYSCALL_64_after_hwframe+0x44/0xa9 159 RIP: 0033:0x7f96443109da 160 RSP: 002b:00007ffcf0b51b08 EFLAGS: 0000020 161 RAX: ffffffffffffffda RBX: 000055dc3ee521a 162 RDX: 00007f96445cff88 RSI: 0000000000057a5 163 RBP: 000055dc3ee510b0 R08: 000000000000000 164 R10: 00007f964430cd0a R11: 000000000000020 165 R13: 000055dc3ee51090 R14: 000000000000000 166 167 Allocated by task 2760: 168 save_stack+0x43/0xd0 169 kasan_kmalloc+0xa7/0xd0 170 kmem_cache_alloc_trace+0xe1/0x1b0 171 kmalloc_oob_right+0x56/0xbc [kasan_test] 172 kmalloc_tests_init+0x16/0x700 [kasan_test 173 do_one_initcall+0xa5/0x3ae 174 do_init_module+0x1b6/0x547 175 load_module+0x75df/0x8070 176 __do_sys_init_module+0x1c6/0x200 177 __x64_sys_init_module+0x6e/0xb0 178 do_syscall_64+0x9f/0x2c0 179 entry_SYSCALL_64_after_hwframe+0x44/0xa9 180 181 Freed by task 815: 182 save_stack+0x43/0xd0 183 __kasan_slab_free+0x135/0x190 184 kasan_slab_free+0xe/0x10 185 kfree+0x93/0x1a0 186 umh_complete+0x6a/0xa0 187 call_usermodehelper_exec_async+0x4c3/0x64 188 ret_from_fork+0x35/0x40 189 190 The buggy address belongs to the object at 191 which belongs to the cache kmalloc-128 of 192 The buggy address is located 123 bytes ins 193 128-byte region [ffff8801f44ec300, ffff88 194 The buggy address belongs to the page: 195 page:ffffea0007d13b00 count:1 mapcount:0 m 196 flags: 0x200000000000100(slab) 197 raw: 0200000000000100 ffffea0007d11dc0 000 198 raw: 0000000000000000 0000000080150015 000 199 page dumped because: kasan: bad access det 200 201 Memory state around the buggy address: 202 ffff8801f44ec200: fc fc fc fc fc fc fc fc 203 ffff8801f44ec280: fb fb fb fb fb fb fb fb 204 >ffff8801f44ec300: 00 00 00 00 00 00 00 00 205 206 ffff8801f44ec380: fc fc fc fc fc fc fc fc 207 ffff8801f44ec400: fb fb fb fb fb fb fb fb 208 ========================================== 209 210 报告标题总结了发生的错误类型以 211 堆栈跟踪、所访问内存分配位置的 212 被释放的位置的堆栈跟踪(对于访 213 slab对象的描述以及关于访问的内存 214 215 最后,报告展示了访问地址周围的 216 内存状态,根据KASAN模式分为8或16 217 都显示了围绕访问地址的其中一个 218 219 对于通用KASAN,每个内存颗粒的大 220 中。这8个字节可以是可访问的,部 221 对每个影子字节使用以下编码:00表 222 (1 <= N <= 7)表示前N个字节可访问, 223 无法访问整个8字节。KASAN使用不同 224 或已释放的内存(参见 mm/kasan/kasan. 225 226 在上面的报告中,箭头指向影子字 227 228 对于基于标签的KASAN模式,报告最 229 (参考 `实施细则`_ 章节)。 230 231 请注意,KASAN错误标题(如 ``slab-out 232 是尽量接近的:KASAN根据其拥有的有 233 可能会有所不同。 234 235 通用KASAN还报告两个辅助调用堆栈 236 出现在错误访问堆栈跟踪中的位置 237 238 CONFIG_KASAN_EXTRA_INFO 239 ~~~~~~~~~~~~~~~~~~~~~~~ 240 241 启用 CONFIG_KASAN_EXTRA_INFO 选项允许 KA 242 额外信息包括分配和释放时的 CPU 243 并将错误与其他系统事件关联起来 244 开销的细节,请参见 CONFIG_KASAN_EXTRA 245 246 以下为 CONFIG_KASAN_EXTRA_INFO 开启后的 247 248 ========================================== 249 ... 250 Allocated by task 134 on cpu 5 at 229.1338 251 ... 252 Freed by task 136 on cpu 3 at 230.199335s: 253 ... 254 ========================================== 255 256 实施细则 257 -------- 258 259 通用KASAN 260 ~~~~~~~~~ 261 262 软件KASAN模式使用影子内存来记录 263 在每次内存访问之前插入影子内存 264 265 通用KASAN将1/8的内核内存专用于其 266 具有比例和偏移量的直接映射将内 267 268 这是将地址转换为其相应影子地址 269 270 static inline void *kasan_mem_to_shadow(co 271 { 272 return (void *)((unsigned long)addr >> 273 + KASAN_SHADOW_OFFSET; 274 } 275 276 在这里 ``KASAN_SHADOW_SCALE_SHIFT = 3`` 。 277 278 编译时工具用于插入内存访问检查 279 插入函数调用( ``__asan_load*(addr)`` , ` 280 检查相应的影子内存来检查内存访 281 282 使用inline插桩,编译器不进行函数 283 显著地增大了内核体积,但与outline 284 285 通用KASAN是唯一一种通过隔离延迟 286 (参见 mm/kasan/quarantine.c 以了解实 287 288 基于软件标签的KASAN模式 289 ~~~~~~~~~~~~~~~~~~~~~~~ 290 291 基于软件标签的KASAN使用软件内存 292 293 基于软件标签的KASAN使用arm64 CPU的 294 存储一个指针标签。它使用影子内 295 它将内核内存的1/16专用于影子内存 296 297 在每次内存分配时,基于软件标签 298 的内存,并将相同的标签嵌入到返 299 300 基于软件标签的KASAN使用编译时工 301 访问的内存的标签等于用于访问该 302 的KASAN会打印错误报告。 303 304 基于软件标签的KASAN也有两种插桩 305 执行内联的影子内存检查)。使用o 306 报告。使用inline插桩,编译器会发 307 来打印错误报告。 308 309 基于软件标签的KASAN使用0xFF作为匹 310 的指针进行的访问)。值0xFE当前保 311 312 313 基于硬件标签的KASAN模式 314 ~~~~~~~~~~~~~~~~~~~~~~~ 315 316 基于硬件标签的KASAN在概念上类似 317 不是编译器插桩和影子内存。 318 319 基于硬件标签的KASAN目前仅针对arm64 320 的arm64内存标记扩展(MTE)和最高字节 321 322 特殊的arm64指令用于为每次内存分 323 的指针。在每次内存访问时,硬件 324 的标签。如果标签不匹配,则会生 325 326 基于硬件标签的KASAN使用0xFF作为匹 327 指针进行的访问)。值0xFE当前保留 328 329 如果硬件不支持MTE(ARMv8.5之前), 330 所有KASAN引导参数都将被忽略。 331 332 请注意,启用CONFIG_KASAN_HW_TAGS始终 333 ``kasan.mode=off`` 或硬件不支持MTE(但 334 335 基于硬件标签的KASAN只报告第一个 336 337 影子内存 338 -------- 339 340 本节的内容只适用于软件KASAN模式 341 342 内核将内存映射到地址空间的几个 343 内存来支持内核可以访问的每个地 344 部分映射真实的影子。 345 346 默认行为 347 ~~~~~~~~ 348 349 默认情况下,体系结构仅将实际内 350 小区域)。对于所有其他区域 —— 351 到阴影区域上。这个只读的影子页 352 353 这给模块带来了一个问题:它们不 354 通过连接模块分配器,KASAN临时映 355 对模块全局变量的无效访问。 356 357 这也造成了与 ``VMAP_STACK`` 的不兼容 358 只读页面的影子内存,并且内核在 359 360 CONFIG_KASAN_VMALLOC 361 ~~~~~~~~~~~~~~~~~~~~ 362 363 使用 ``CONFIG_KASAN_VMALLOC`` ,KASAN可以 364 空间。目前,这在arm64、x86、riscv、 365 366 这通过连接到vmalloc和vmap并动态分 367 368 vmalloc空间中的大多数映射都很小, 369 分配一个完整的影子页面将是一种 370 页面,映射必须与 ``KASAN_GRANULE_SIZE 371 372 相反,KASAN跨多个映射共享后备空 373 页面时,它会分配一个后备页面。 374 375 KASAN连接到vmap基础架构以懒清理未 376 377 为了避免交换映射的困难,KASAN预 378 的阴影页面覆盖,但是将不会被映 379 380 这允许在x86上支持 ``VMAP_STACK`` ,并 381 382 对于开发者 383 ---------- 384 385 忽略访问 386 ~~~~~~~~ 387 388 软件KASAN模式使用编译器插桩来插 389 不兼容,因此需要禁用。 390 391 内核的其他部分可能会访问已分配 392 但在某些情况下(例如,在内存分 393 394 对于软件KASAN模式,要禁用特定文 395 到相应的内核Makefile中: 396 397 - 对于单个文件(例如,main.o):: 398 399 KASAN_SANITIZE_main.o := n 400 401 - 对于一个目录下的所有文件:: 402 403 KASAN_SANITIZE := n 404 405 对于软件KASAN模式,要在每个函数 406 ``__no_sanitize_address`` 函数属性或通 407 408 请注意,禁用编译器插桩(基于每 409 的代码中直接发生的访问。当访问 410 插桩的基于硬件标签的模式时,它 411 412 对于软件KASAN模式,要在当前任务 413 ``kasan_disable_current()``/``kasan_enable_cur 414 这也会禁用通过函数调用发生的间 415 416 对于基于标签的KASAN模式,要禁用 417 ``page_kasan_tag_reset()`` 。请注意,通 418 临时禁用访问检查需要通过 ``page_ka 419 存和恢复每页KASAN标签。 420 421 测试 422 ~~~~ 423 424 有一些KASAN测试可以验证KASAN是否正 425 测试由两部分组成: 426 427 1. 与KUnit测试框架集成的测试。使 428 这些测试可以通过几种不同的方式 429 430 2. 与KUnit不兼容的测试。使用 ``CONFI 431 运行。这些测试只能通过加载内核 432 433 如果检测到错误,每个KUnit兼容的KA 434 其编号和状态。 435 436 当测试通过:: 437 438 ok 28 - kmalloc_double_kzfree 439 440 当由于 ``kmalloc`` 失败而导致测试失 441 442 # kmalloc_large_oob_right: ASSERTION F 443 Expected ptr is not null, but is 444 not ok 5 - kmalloc_large_oob_right 445 446 当由于缺少KASAN报告而导致测试失 447 448 # kmalloc_double_kzfree: EXPECTATION F 449 KASAN failure expected in "kfree_sensi 450 not ok 28 - kmalloc_double_kzfree 451 452 453 最后打印所有KASAN测试的累积状态 454 455 ok 1 - kasan 456 457 或者,如果其中一项测试失败:: 458 459 not ok 1 - kasan 460 461 有几种方法可以运行与KUnit兼容的KA 462 463 1. 可加载模块 464 465 启用 ``CONFIG_KUNIT`` 后,KASAN-KUnit 466 ``insmod`` 或 ``modprobe`` 加载 ``kasan_ 467 468 2. 内置 469 470 通过内置 ``CONFIG_KUNIT`` ,也可以 471 测试将在启动时作为后期初始化 472 473 3. 使用kunit_tool 474 475 通过内置 ``CONFIG_KUNIT`` 和 ``CONFIG_ 476 ``kunit_tool`` 以更易读的方式查看K 477 的KASAN报告。有关 ``kunit_tool`` 更 478 `KUnit文档 <https://www.kernel.org/doc/ht 479 480 .. _KUnit: https://www.kernel.org/doc/html/lat
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.