1 .. SPDX-License-Identifier: GPL-2.0 2 3 .. include:: ../disclaimer-zh_TW.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 實施細則 239 -------- 240 241 通用KASAN 242 ~~~~~~~~~ 243 244 軟件KASAN模式使用影子內存來記錄 245 在每次內存訪問之前插入影子內存 246 247 通用KASAN將1/8的內核內存專用於其 248 具有比例和偏移量的直接映射將內 249 250 這是將地址轉換爲其相應影子地址 251 252 static inline void *kasan_mem_to_shadow(co 253 { 254 return (void *)((unsigned long)addr >> 255 + KASAN_SHADOW_OFFSET; 256 } 257 258 在這裏 ``KASAN_SHADOW_SCALE_SHIFT = 3`` 。 259 260 編譯時工具用於插入內存訪問檢查 261 插入函數調用( ``__asan_load*(addr)`` , ` 262 檢查相應的影子內存來檢查內存訪 263 264 使用inline插樁,編譯器不進行函數 265 顯著地增大了內核體積,但與outline 266 267 通用KASAN是唯一一種通過隔離延遲 268 (參見 mm/kasan/quarantine.c 以瞭解實 269 270 基於軟件標籤的KASAN模式 271 ~~~~~~~~~~~~~~~~~~~~~~~ 272 273 基於軟件標籤的KASAN使用軟件內存 274 275 基於軟件標籤的KASAN使用arm64 CPU的 276 存儲一個指針標籤。它使用影子內 277 它將內核內存的1/16專用於影子內存 278 279 在每次內存分配時,基於軟件標籤 280 的內存,並將相同的標籤嵌入到返 281 282 基於軟件標籤的KASAN使用編譯時工 283 訪問的內存的標籤等於用於訪問該 284 的KASAN會打印錯誤報告。 285 286 基於軟件標籤的KASAN也有兩種插樁 287 執行內聯的影子內存檢查)。使用o 288 報告。使用inline插樁,編譯器會發 289 來打印錯誤報告。 290 291 基於軟件標籤的KASAN使用0xFF作爲匹 292 的指針進行的訪問)。值0xFE當前保 293 294 295 基於硬件標籤的KASAN模式 296 ~~~~~~~~~~~~~~~~~~~~~~~ 297 298 基於硬件標籤的KASAN在概念上類似 299 不是編譯器插樁和影子內存。 300 301 基於硬件標籤的KASAN目前僅針對arm64 302 的arm64內存標記擴展(MTE)和最高字節 303 304 特殊的arm64指令用於爲每次內存分 305 的指針。在每次內存訪問時,硬件 306 的標籤。如果標籤不匹配,則會生 307 308 基於硬件標籤的KASAN使用0xFF作爲匹 309 指針進行的訪問)。值0xFE當前保留 310 311 如果硬件不支持MTE(ARMv8.5之前), 312 所有KASAN引導參數都將被忽略。 313 314 請注意,啓用CONFIG_KASAN_HW_TAGS始終 315 ``kasan.mode=off`` 或硬件不支持MTE(但 316 317 基於硬件標籤的KASAN只報告第一個 318 319 影子內存 320 -------- 321 322 本節的內容只適用於軟件KASAN模式 323 324 內核將內存映射到地址空間的幾個 325 內存來支持內核可以訪問的每個地 326 部分映射真實的影子。 327 328 默認行爲 329 ~~~~~~~~ 330 331 默認情況下,體系結構僅將實際內 332 小區域)。對於所有其他區域 —— 333 到陰影區域上。這個只讀的影子頁 334 335 這給模塊帶來了一個問題:它們不 336 通過連接模塊分配器,KASAN臨時映 337 對模塊全局變量的無效訪問。 338 339 這也造成了與 ``VMAP_STACK`` 的不兼容 340 只讀頁面的影子內存,並且內核在 341 342 CONFIG_KASAN_VMALLOC 343 ~~~~~~~~~~~~~~~~~~~~ 344 345 使用 ``CONFIG_KASAN_VMALLOC`` ,KASAN可以 346 空間。目前,這在arm64、x86、riscv、 347 348 這通過連接到vmalloc和vmap並動態分 349 350 vmalloc空間中的大多數映射都很小, 351 分配一個完整的影子頁面將是一種 352 頁面,映射必須與 ``KASAN_GRANULE_SIZE 353 354 相反,KASAN跨多個映射共享後備空 355 頁面時,它會分配一個後備頁面。 356 357 KASAN連接到vmap基礎架構以懶清理未 358 359 爲了避免交換映射的困難,KASAN預 360 的陰影頁面覆蓋,但是將不會被映 361 362 這允許在x86上支持 ``VMAP_STACK`` ,並 363 364 對於開發者 365 ---------- 366 367 忽略訪問 368 ~~~~~~~~ 369 370 軟件KASAN模式使用編譯器插樁來插 371 不兼容,因此需要禁用。 372 373 內核的其他部分可能會訪問已分配 374 但在某些情況下(例如,在內存分 375 376 對於軟件KASAN模式,要禁用特定文 377 到相應的內核Makefile中: 378 379 - 對於單個文件(例如,main.o):: 380 381 KASAN_SANITIZE_main.o := n 382 383 - 對於一個目錄下的所有文件:: 384 385 KASAN_SANITIZE := n 386 387 對於軟件KASAN模式,要在每個函數 388 ``__no_sanitize_address`` 函數屬性或通 389 390 請注意,禁用編譯器插樁(基於每 391 的代碼中直接發生的訪問。當訪問 392 插樁的基於硬件標籤的模式時,它 393 394 對於軟件KASAN模式,要在當前任務 395 ``kasan_disable_current()``/``kasan_enable_cur 396 這也會禁用通過函數調用發生的間 397 398 對於基於標籤的KASAN模式,要禁用 399 ``page_kasan_tag_reset()`` 。請注意,通 400 臨時禁用訪問檢查需要通過 ``page_ka 401 存和恢復每頁KASAN標籤。 402 403 測試 404 ~~~~ 405 406 有一些KASAN測試可以驗證KASAN是否正 407 測試由兩部分組成: 408 409 1. 與KUnit測試框架集成的測試。使 410 這些測試可以通過幾種不同的方式 411 412 2. 與KUnit不兼容的測試。使用 ``CONFI 413 運行。這些測試只能通過加載內核 414 415 如果檢測到錯誤,每個KUnit兼容的KA 416 其編號和狀態。 417 418 當測試通過:: 419 420 ok 28 - kmalloc_double_kzfree 421 422 當由於 ``kmalloc`` 失敗而導致測試失 423 424 # kmalloc_large_oob_right: ASSERTION F 425 Expected ptr is not null, but is 426 not ok 5 - kmalloc_large_oob_right 427 428 當由於缺少KASAN報告而導致測試失 429 430 # kmalloc_double_kzfree: EXPECTATION F 431 KASAN failure expected in "kfree_sensi 432 not ok 28 - kmalloc_double_kzfree 433 434 435 最後打印所有KASAN測試的累積狀態 436 437 ok 1 - kasan 438 439 或者,如果其中一項測試失敗:: 440 441 not ok 1 - kasan 442 443 有幾種方法可以運行與KUnit兼容的KA 444 445 1. 可加載模塊 446 447 啓用 ``CONFIG_KUNIT`` 後,KASAN-KUnit 448 ``insmod`` 或 ``modprobe`` 加載 ``kasan_ 449 450 2. 內置 451 452 通過內置 ``CONFIG_KUNIT`` ,也可以 453 測試將在啓動時作爲後期初始化 454 455 3. 使用kunit_tool 456 457 通過內置 ``CONFIG_KUNIT`` 和 ``CONFIG_ 458 ``kunit_tool`` 以更易讀的方式查看K 459 的KASAN報告。有關 ``kunit_tool`` 更 460 `KUnit文檔 <https://www.kernel.org/doc/ht 461 462 .. _KUnit: https://www.kernel.org/doc/html/lat 463
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.