.. SPDX-License-Identifier: GPL-2.0 .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/dev-tools/kasan.rst :Translator: 万家兵 Wan Jiabing <wanjiabing@vivo.com> å†…æ ¸åœ°å€æ¶ˆæ¯’剂(KASAN) ===================== 概述 ---- Kernel Address SANitizer(KASAN)是一ç§åŠ¨æ€å†…å˜å®‰å…¨é”™è¯¯æ£€æµ‹å·¥å…·ï¼Œä¸»è¦åŠŸèƒ½æ˜¯ 检查内å˜è¶Šç•Œè®¿é—®å’Œä½¿ç”¨å·²é‡Šæ”¾å†…å˜çš„问题。 KASAN有三ç§æ¨¡å¼: 1. 通用KASAN 2. åŸºäºŽè½¯ä»¶æ ‡ç¾çš„KASAN 3. åŸºäºŽç¡¬ä»¶æ ‡ç¾çš„KASAN 用CONFIG_KASAN_GENERICå¯ç”¨çš„通用KASAN,是用于调试的模å¼ï¼Œç±»ä¼¼äºŽç”¨æˆ·ç©º é—´çš„ASan。这ç§æ¨¡å¼åœ¨è®¸å¤šCPU架构上都被支æŒï¼Œä½†å®ƒæœ‰æ˜Žæ˜¾çš„性能和内å˜å¼€é”€ã€‚ åŸºäºŽè½¯ä»¶æ ‡ç¾çš„KASAN或SW_TAGS KASAN,通过CONFIG_KASAN_SW_TAGSå¯ç”¨ï¼Œ å¯ä»¥ç”¨äºŽè°ƒè¯•å’Œè‡ªæˆ‘测试,类似于用户空间HWASan。这ç§æ¨¡å¼åªæ”¯æŒarm64,但其 适度的内å˜å¼€é”€å…许在内å˜å—é™çš„设备上用真实的工作负载进行测试。 åŸºäºŽç¡¬ä»¶æ ‡ç¾çš„KASAN或HW_TAGS KASAN,用CONFIG_KASAN_HW_TAGSå¯ç”¨ï¼Œè¢« 用作现场内å˜é”™è¯¯æ£€æµ‹å™¨æˆ–作为安全缓解的模å¼ã€‚è¿™ç§æ¨¡å¼åªåœ¨æ”¯æŒMTE(内å˜æ ‡ç¾ 扩展)的arm64 CPU上工作,但它的内å˜å’Œæ€§èƒ½å¼€é”€å¾ˆä½Žï¼Œå› æ¤å¯ä»¥åœ¨ç”Ÿäº§ä¸ä½¿ç”¨ã€‚ 关于æ¯ç§KASAN模å¼çš„内å˜å’Œæ€§èƒ½å½±å“的细节,请å‚è§ç›¸åº”çš„Kconfig选项的æ述。 通用模å¼å’ŒåŸºäºŽè½¯ä»¶æ ‡ç¾çš„模å¼é€šå¸¸è¢«ç§°ä¸ºè½¯ä»¶æ¨¡å¼ã€‚åŸºäºŽè½¯ä»¶æ ‡ç¾çš„模å¼å’ŒåŸºäºŽ ç¡¬ä»¶æ ‡ç¾çš„模å¼è¢«ç§°ä¸ºåŸºäºŽæ ‡ç¾çš„模å¼ã€‚ æ”¯æŒ ---- 体系架构 ~~~~~~~~ 在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。 用法 ---- è¦å¯ç”¨KASAN,请使用以下命令é…ç½®å†…æ ¸:: CONFIG_KASAN=y åŒæ—¶åœ¨ ``CONFIG_KASAN_GENERIC`` (å¯ç”¨é€šç”¨KASAN模å¼), ``CONFIG_KASAN_SW_TAGS`` (å¯ç”¨åŸºäºŽç¡¬ä»¶æ ‡ç¾çš„KASAN模å¼),和 ``CONFIG_KASAN_HW_TAGS`` (å¯ç”¨åŸºäºŽç¡¬ä»¶æ ‡ç¾ çš„KASAN模å¼)之间进行选择。 对于软件模å¼ï¼Œè¿˜å¯ä»¥åœ¨ ``CONFIG_KASAN_OUTLINE`` å’Œ ``CONFIG_KASAN_INLINE`` 之间进行选择。outlineå’Œinline是编译器æ’桩类型。å‰è€…产生较å°çš„二进制文件, 而åŽè€…å¿«2å€ã€‚ è¦å°†å—å½±å“çš„slab对象的allocå’Œfreeå †æ ˆè·Ÿè¸ªåŒ…å«åˆ°æŠ¥å‘Šä¸ï¼Œè¯·å¯ç”¨ ``CONFIG_STACKTRACE`` 。è¦åŒ…括å—å½±å“物ç†é¡µé¢çš„分é…å’Œé‡Šæ”¾å †æ ˆè·Ÿè¸ªçš„è¯ï¼Œ 请å¯ç”¨ ``CONFIG_PAGE_OWNER`` 并使用 ``page_owner=on`` 进行引导。 å¯åŠ¨å‚æ•° ~~~~~~~~ KASANå—到通用 ``panic_on_warn`` 命令行å‚æ•°çš„å½±å“。当它被å¯ç”¨æ—¶ï¼ŒKASAN 在打å°å‡ºé”™è¯¯æŠ¥å‘ŠåŽä¼šä½¿å†…æ ¸æ慌。 默认情况下,KASANåªå¯¹ç¬¬ä¸€ä¸ªæ— 效的内å˜è®¿é—®æ‰“å°é”™è¯¯æŠ¥å‘Šã€‚使用 ``kasan_multi_shot``,KASAN对æ¯ä¸€ä¸ªæ— 效的访问都打å°ä¸€ä»½æŠ¥å‘Šã€‚这会ç¦ç”¨ 了KASAN报告的 ``panic_on_warn``。 å¦å¤–,独立于 ``panic_on_warn`` 〠``kasan.fault=`` bootå‚æ•°å¯ä»¥ç”¨ æ¥æŽ§åˆ¶æ慌和报告行为。 - ``kasan.fault=report`` 或 ``=panic`` 控制是å¦åªæ‰“å°KASAN report或 åŒæ—¶ä½¿å†…æ ¸æ慌(默认: ``report`` )。å³ä½¿ ``kasan_multi_shot`` 被 å¯ç”¨ï¼Œæ慌也会å‘生。 åŸºäºŽè½¯ä»¶å’Œç¡¬ä»¶æ ‡ç¾çš„KASAN模å¼ï¼ˆè§ä¸‹é¢å…³äºŽå„ç§æ¨¡å¼çš„部分)支æŒæ”¹å˜å †æ ˆè·Ÿ 踪收集行为: - ``kasan.stacktrace=off`` 或 ``=on`` ç¦ç”¨æˆ–å¯ç”¨åˆ†é…å’Œé‡Šæ”¾å †æ ˆç—• 迹的收集(默认: ``on`` )。 - ``kasan.stack_ring_size=<number of entries>`` æŒ‡å®šå †æ ˆçŽ¯çš„æ¡ ç›®æ•°ï¼ˆé»˜è®¤ï¼š ``32768`` )。 åŸºäºŽç¡¬ä»¶æ ‡ç¾çš„KASAN模å¼æ˜¯ä¸ºäº†åœ¨ç”Ÿäº§ä¸ä½œä¸ºä¸€ç§å®‰å…¨ç¼“è§£æŽªæ–½ä½¿ç”¨ã€‚å› æ¤ï¼Œå®ƒ 支æŒé¢å¤–çš„å¯åŠ¨å‚数,å…许完全ç¦ç”¨KASAN或控制其功能。 - ``kasan=off`` 或 ``=on`` 控制KASAN是å¦è¢«å¯ç”¨ï¼ˆé»˜è®¤ï¼š ``on`` )。 - ``kasan.mode=sync``, ``=async`` or ``=asymm`` 控制KASANæ˜¯å¦ è¢«é…置为åŒæ¥ã€å¼‚æ¥æˆ–éžå¯¹ç§°çš„执行模å¼ï¼ˆé»˜è®¤ï¼š ``åŒæ¥`` )。 åŒæ¥æ¨¡å¼ï¼šå½“æ ‡ç¾æ£€æŸ¥å¼‚常å‘生时,会立å³æ£€æµ‹åˆ°ä¸è‰¯è®¿é—®ã€‚ 异æ¥æ¨¡å¼ï¼šä¸è‰¯è®¿é—®çš„æ£€æµ‹æ˜¯å»¶è¿Ÿçš„ã€‚å½“æ ‡ç¾æ£€æŸ¥å¼‚常å‘生时,信æ¯è¢«å˜å‚¨åœ¨ç¡¬ 件ä¸ï¼ˆå¯¹äºŽarm64æ¥è¯´æ˜¯åœ¨TFSR_EL1寄å˜å™¨ä¸ï¼‰ã€‚å†…æ ¸å‘¨æœŸæ€§åœ°æ£€æŸ¥ç¡¬ä»¶ï¼Œå¹¶\ 且åªåœ¨è¿™äº›æ£€æŸ¥ä¸æŠ¥å‘Šæ ‡ç¾å¼‚常。 éžå¯¹ç§°æ¨¡å¼ï¼šè¯»å–æ—¶åŒæ¥æ£€æµ‹ä¸è‰¯è®¿é—®ï¼Œå†™å…¥æ—¶å¼‚æ¥æ£€æµ‹ã€‚ - ``kasan.vmalloc=off`` or ``=on`` ç¦ç”¨æˆ–å¯ç”¨vmalloc分é…çš„æ ‡è®°ï¼ˆé»˜è®¤ï¼š ``on`` )。 错误报告 ~~~~~~~~ 典型的KASAN报告如下所示:: ================================================================== BUG: KASAN: slab-out-of-bounds in kmalloc_oob_right+0xa8/0xbc [test_kasan] Write of size 1 at addr ffff8801f44ec37b by task insmod/2760 CPU: 1 PID: 2760 Comm: insmod Not tainted 4.19.0-rc3+ #698 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014 Call Trace: dump_stack+0x94/0xd8 print_address_description+0x73/0x280 kasan_report+0x144/0x187 __asan_report_store1_noabort+0x17/0x20 kmalloc_oob_right+0xa8/0xbc [test_kasan] kmalloc_tests_init+0x16/0x700 [test_kasan] do_one_initcall+0xa5/0x3ae do_init_module+0x1b6/0x547 load_module+0x75df/0x8070 __do_sys_init_module+0x1c6/0x200 __x64_sys_init_module+0x6e/0xb0 do_syscall_64+0x9f/0x2c0 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x7f96443109da RSP: 002b:00007ffcf0b51b08 EFLAGS: 00000202 ORIG_RAX: 00000000000000af RAX: ffffffffffffffda RBX: 000055dc3ee521a0 RCX: 00007f96443109da RDX: 00007f96445cff88 RSI: 0000000000057a50 RDI: 00007f9644992000 RBP: 000055dc3ee510b0 R08: 0000000000000003 R09: 0000000000000000 R10: 00007f964430cd0a R11: 0000000000000202 R12: 00007f96445cff88 R13: 000055dc3ee51090 R14: 0000000000000000 R15: 0000000000000000 Allocated by task 2760: save_stack+0x43/0xd0 kasan_kmalloc+0xa7/0xd0 kmem_cache_alloc_trace+0xe1/0x1b0 kmalloc_oob_right+0x56/0xbc [test_kasan] kmalloc_tests_init+0x16/0x700 [test_kasan] do_one_initcall+0xa5/0x3ae do_init_module+0x1b6/0x547 load_module+0x75df/0x8070 __do_sys_init_module+0x1c6/0x200 __x64_sys_init_module+0x6e/0xb0 do_syscall_64+0x9f/0x2c0 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Freed by task 815: save_stack+0x43/0xd0 __kasan_slab_free+0x135/0x190 kasan_slab_free+0xe/0x10 kfree+0x93/0x1a0 umh_complete+0x6a/0xa0 call_usermodehelper_exec_async+0x4c3/0x640 ret_from_fork+0x35/0x40 The buggy address belongs to the object at ffff8801f44ec300 which belongs to the cache kmalloc-128 of size 128 The buggy address is located 123 bytes inside of 128-byte region [ffff8801f44ec300, ffff8801f44ec380) The buggy address belongs to the page: page:ffffea0007d13b00 count:1 mapcount:0 mapping:ffff8801f7001640 index:0x0 flags: 0x200000000000100(slab) raw: 0200000000000100 ffffea0007d11dc0 0000001a0000001a ffff8801f7001640 raw: 0000000000000000 0000000080150015 00000001ffffffff 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff8801f44ec200: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb ffff8801f44ec280: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc >ffff8801f44ec300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ^ ffff8801f44ec380: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb ffff8801f44ec400: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ================================================================== æŠ¥å‘Šæ ‡é¢˜æ€»ç»“äº†å‘生的错误类型以åŠå¯¼è‡´è¯¥é”™è¯¯çš„访问类型。紧éšå…¶åŽçš„是错误访问的 å †æ ˆè·Ÿè¸ªã€æ‰€è®¿é—®å†…å˜åˆ†é…ä½ç½®çš„å †æ ˆè·Ÿè¸ªï¼ˆå¯¹äºŽè®¿é—®äº†slab对象的情况)以åŠå¯¹è±¡ 被释放的ä½ç½®çš„å †æ ˆè·Ÿè¸ªï¼ˆå¯¹äºŽè®¿é—®å·²é‡Šæ”¾å†…å˜çš„问题报告)。接下æ¥æ˜¯å¯¹è®¿é—®çš„ slab对象的æ述以åŠå…³äºŽè®¿é—®çš„内å˜é¡µçš„ä¿¡æ¯ã€‚ 最åŽï¼ŒæŠ¥å‘Šå±•ç¤ºäº†è®¿é—®åœ°å€å‘¨å›´çš„内å˜çŠ¶æ€ã€‚在内部,KASANå•ç‹¬è·Ÿè¸ªæ¯ä¸ªå†…å˜é¢—ç²’çš„ 内å˜çŠ¶æ€ï¼Œæ ¹æ®KASAN模å¼åˆ†ä¸º8或16个对é½å—节。报告的内å˜çŠ¶æ€éƒ¨åˆ†ä¸çš„æ¯ä¸ªæ•°å— 都显示了围绕访问地å€çš„å…¶ä¸ä¸€ä¸ªå†…å˜é¢—粒的状æ€ã€‚ 对于通用KASAN,æ¯ä¸ªå†…å˜é¢—粒的大å°ä¸º8个å—节。æ¯ä¸ªé¢—粒的状æ€è¢«ç¼–ç 在一个影åå—节 ä¸ã€‚è¿™8个å—节å¯ä»¥æ˜¯å¯è®¿é—®çš„,部分访问的,已释放的或æˆä¸ºRedzone的一部分。KASAN 对æ¯ä¸ªå½±åå—节使用以下编ç :00表示对应内å˜åŒºåŸŸçš„所有8个å—节都å¯ä»¥è®¿é—®ï¼›æ•°å—N (1 <= N <= 7)表示å‰N个å—节å¯è®¿é—®ï¼Œå…¶ä»–(8 - N)个å—节ä¸å¯è®¿é—®ï¼›ä»»ä½•è´Ÿå€¼éƒ½è¡¨ç¤º æ— æ³•è®¿é—®æ•´ä¸ª8å—节。KASAN使用ä¸åŒçš„负值æ¥åŒºåˆ†ä¸åŒç±»åž‹çš„ä¸å¯è®¿é—®å†…å˜ï¼Œå¦‚redzones 或已释放的内å˜ï¼ˆå‚è§ mm/kasan/kasan.h)。 在上é¢çš„报告ä¸ï¼Œç®å¤´æŒ‡å‘å½±åå—节 ``03`` ,表示访问的地å€æ˜¯éƒ¨åˆ†å¯è®¿é—®çš„。 å¯¹äºŽåŸºäºŽæ ‡ç¾çš„KASAN模å¼ï¼ŒæŠ¥å‘Šæœ€åŽçš„部分显示了访问地å€å‘¨å›´çš„内å˜æ ‡ç¾ (å‚考 `实施细则`_ ç« èŠ‚)。 请注æ„,KASANé”™è¯¯æ ‡é¢˜ï¼ˆå¦‚ ``slab-out-of-bounds`` 或 ``use-after-free`` ) 是尽é‡æŽ¥è¿‘çš„:KASANæ ¹æ®å…¶æ‹¥æœ‰çš„有é™ä¿¡æ¯æ‰“å°å‡ºæœ€å¯èƒ½çš„错误类型。错误的实际类型 å¯èƒ½ä¼šæœ‰æ‰€ä¸åŒã€‚ 通用KASANè¿˜æŠ¥å‘Šä¸¤ä¸ªè¾…åŠ©è°ƒç”¨å †æ ˆè·Ÿè¸ªã€‚è¿™äº›å †æ ˆè·Ÿè¸ªæŒ‡å‘代ç ä¸ä¸Žå¯¹è±¡äº¤äº’但ä¸ç›´æŽ¥ å‡ºçŽ°åœ¨é”™è¯¯è®¿é—®å †æ ˆè·Ÿè¸ªä¸çš„ä½ç½®ã€‚ç›®å‰ï¼Œè¿™åŒ…括 call_rcu() 和排队的工作队列。 实施细则 -------- 通用KASAN ~~~~~~~~~ 软件KASAN模å¼ä½¿ç”¨å½±å内å˜æ¥è®°å½•æ¯ä¸ªå†…å˜å—节是å¦å¯ä»¥å®‰å…¨è®¿é—®ï¼Œå¹¶ä½¿ç”¨ç¼–译时工具 在æ¯æ¬¡å†…å˜è®¿é—®ä¹‹å‰æ’入影å内å˜æ£€æŸ¥ã€‚ 通用KASANå°†1/8çš„å†…æ ¸å†…å˜ä¸“用于其影å内å˜ï¼ˆ16TB以覆盖x86_64上的128TB),并使用 具有比例和å移é‡çš„ç›´æŽ¥æ˜ å°„å°†å†…å˜åœ°å€è½¬æ¢ä¸ºå…¶ç›¸åº”çš„å½±å地å€ã€‚ 这是将地å€è½¬æ¢ä¸ºå…¶ç›¸åº”å½±å地å€çš„函数:: static inline void *kasan_mem_to_shadow(const void *addr) { return (void *)((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT) + KASAN_SHADOW_OFFSET; } 在这里 ``KASAN_SHADOW_SCALE_SHIFT = 3`` 。 编译时工具用于æ’入内å˜è®¿é—®æ£€æŸ¥ã€‚编译器在æ¯æ¬¡è®¿é—®å¤§å°ä¸º1ã€2ã€4ã€8或16的内å˜ä¹‹å‰ æ’入函数调用( ``__asan_load*(addr)`` , ``__asan_store*(addr)``)。这些函数通过 检查相应的影å内å˜æ¥æ£€æŸ¥å†…å˜è®¿é—®æ˜¯å¦æœ‰æ•ˆã€‚ 使用inlineæ’桩,编译器ä¸è¿›è¡Œå‡½æ•°è°ƒç”¨ï¼Œè€Œæ˜¯ç›´æŽ¥æ’入代ç æ¥æ£€æŸ¥å½±å内å˜ã€‚æ¤é€‰é¡¹ æ˜¾è‘—åœ°å¢žå¤§äº†å†…æ ¸ä½“ç§¯ï¼Œä½†ä¸Žoutlineæ’æ¡©å†…æ ¸ç›¸æ¯”ï¼Œå®ƒæ供了x1.1-x2的性能æå‡ã€‚ 通用KASAN是唯一一ç§é€šè¿‡éš”离延迟é‡æ–°ä½¿ç”¨å·²é‡Šæ”¾å¯¹è±¡çš„æ¨¡å¼ ï¼ˆå‚è§ mm/kasan/quarantine.c 以了解实现)。 åŸºäºŽè½¯ä»¶æ ‡ç¾çš„KASANæ¨¡å¼ ~~~~~~~~~~~~~~~~~~~~~~~ åŸºäºŽè½¯ä»¶æ ‡ç¾çš„KASAN使用软件内å˜æ ‡ç¾æ–¹æ³•æ¥æ£€æŸ¥è®¿é—®æœ‰æ•ˆæ€§ã€‚ç›®å‰ä»…针对arm64架构实现。 åŸºäºŽè½¯ä»¶æ ‡ç¾çš„KASAN使用arm64 CPU的顶部å—节忽略(TBI)ç‰¹æ€§åœ¨å†…æ ¸æŒ‡é’ˆçš„é¡¶éƒ¨å—èŠ‚ä¸ å˜å‚¨ä¸€ä¸ªæŒ‡é’ˆæ ‡ç¾ã€‚它使用影å内å˜æ¥å˜å‚¨ä¸Žæ¯ä¸ª16å—节内å˜å•å…ƒç›¸å…³çš„内å˜æ ‡ç¾(å› æ¤ï¼Œ å®ƒå°†å†…æ ¸å†…å˜çš„1/16专用于影å内å˜)。 在æ¯æ¬¡å†…å˜åˆ†é…æ—¶ï¼ŒåŸºäºŽè½¯ä»¶æ ‡ç¾çš„KASAN都会生æˆä¸€ä¸ªéšæœºæ ‡ç¾ï¼Œç”¨è¿™ä¸ªæ ‡ç¾æ ‡è®°åˆ†é… 的内å˜ï¼Œå¹¶å°†ç›¸åŒçš„æ ‡ç¾åµŒå…¥åˆ°è¿”回的指针ä¸ã€‚ åŸºäºŽè½¯ä»¶æ ‡ç¾çš„KASAN使用编译时工具在æ¯æ¬¡å†…å˜è®¿é—®ä¹‹å‰æ’入检查。这些检查确ä¿æ£åœ¨ 访问的内å˜çš„æ ‡ç¾ç‰äºŽç”¨äºŽè®¿é—®è¯¥å†…å˜çš„æŒ‡é’ˆçš„æ ‡ç¾ã€‚å¦‚æžœæ ‡ç¾ä¸åŒ¹é…ï¼ŒåŸºäºŽè½¯ä»¶æ ‡ç¾ çš„KASAN会打å°é”™è¯¯æŠ¥å‘Šã€‚ åŸºäºŽè½¯ä»¶æ ‡ç¾çš„KASAN也有两ç§æ’桩模å¼ï¼ˆoutline,å‘出回调æ¥æ£€æŸ¥å†…å˜è®¿é—®ï¼›inline, 执行内è”çš„å½±å内å˜æ£€æŸ¥ï¼‰ã€‚使用outlineæ’桩模å¼ï¼Œä¼šä»Žæ‰§è¡Œè®¿é—®æ£€æŸ¥çš„函数打å°é”™è¯¯ 报告。使用inlineæ’桩,编译器会å‘出 ``brk`` 指令,并使用专用的 ``brk`` 处ç†ç¨‹åº æ¥æ‰“å°é”™è¯¯æŠ¥å‘Šã€‚ åŸºäºŽè½¯ä»¶æ ‡ç¾çš„KASAN使用0xFF作为匹é…æ‰€æœ‰æŒ‡é’ˆæ ‡ç¾ï¼ˆä¸æ£€æŸ¥é€šè¿‡å¸¦æœ‰0xFFæŒ‡é’ˆæ ‡ç¾ çš„æŒ‡é’ˆè¿›è¡Œçš„è®¿é—®ï¼‰ã€‚å€¼0xFE当å‰ä¿ç•™ç”¨äºŽæ ‡è®°å·²é‡Šæ”¾çš„内å˜åŒºåŸŸã€‚ åŸºäºŽç¡¬ä»¶æ ‡ç¾çš„KASANæ¨¡å¼ ~~~~~~~~~~~~~~~~~~~~~~~ åŸºäºŽç¡¬ä»¶æ ‡ç¾çš„KASAN在概念上类似于软件模å¼ï¼Œä½†å®ƒæ˜¯ä½¿ç”¨ç¡¬ä»¶å†…å˜æ ‡ç¾ä½œä¸ºæ”¯æŒè€Œ ä¸æ˜¯ç¼–译器æ’桩和影å内å˜ã€‚ åŸºäºŽç¡¬ä»¶æ ‡ç¾çš„KASANç›®å‰ä»…针对arm64架构实现,并且基于ARMv8.5指令集架构ä¸å¼•å…¥ çš„arm64内å˜æ ‡è®°æ‰©å±•(MTE)和最高å—节忽略(TBI)。 特殊的arm64指令用于为æ¯æ¬¡å†…å˜åˆ†é…指定内å˜æ ‡ç¾ã€‚相åŒçš„æ ‡ç¾è¢«æŒ‡å®šç»™æŒ‡å‘è¿™äº›åˆ†é… çš„æŒ‡é’ˆã€‚åœ¨æ¯æ¬¡å†…å˜è®¿é—®æ—¶ï¼Œç¡¬ä»¶ç¡®ä¿æ£åœ¨è®¿é—®çš„内å˜çš„æ ‡ç¾ç‰äºŽç”¨äºŽè®¿é—®è¯¥å†…å˜çš„指针 çš„æ ‡ç¾ã€‚å¦‚æžœæ ‡ç¾ä¸åŒ¹é…,则会生æˆæ•…障并打å°æŠ¥å‘Šã€‚ åŸºäºŽç¡¬ä»¶æ ‡ç¾çš„KASAN使用0xFF作为匹é…æ‰€æœ‰æŒ‡é’ˆæ ‡ç¾ï¼ˆä¸æ£€æŸ¥é€šè¿‡å¸¦æœ‰0xFFæŒ‡é’ˆæ ‡ç¾çš„ 指针进行的访问)。值0xFE当å‰ä¿ç•™ç”¨äºŽæ ‡è®°å·²é‡Šæ”¾çš„内å˜åŒºåŸŸã€‚ 如果硬件ä¸æ”¯æŒMTE(ARMv8.5之å‰ï¼‰ï¼Œåˆ™ä¸ä¼šå¯ç”¨åŸºäºŽç¡¬ä»¶æ ‡ç¾çš„KASAN。在这ç§æƒ…况下, 所有KASAN引导å‚数都将被忽略。 请注æ„,å¯ç”¨CONFIG_KASAN_HW_TAGS始终会导致å¯ç”¨å†…æ ¸ä¸çš„TBI。å³ä½¿æ供了 ``kasan.mode=off`` 或硬件ä¸æ”¯æŒMTE(但支æŒTBI)。 åŸºäºŽç¡¬ä»¶æ ‡ç¾çš„KASANåªæŠ¥å‘Šç¬¬ä¸€ä¸ªå‘现的错误。之åŽï¼ŒMTEæ ‡ç¾æ£€æŸ¥å°†è¢«ç¦ç”¨ã€‚ å½±åå†…å˜ -------- 本节的内容åªé€‚用于软件KASAN模å¼ã€‚ å†…æ ¸å°†å†…å˜æ˜ 射到地å€ç©ºé—´çš„å‡ ä¸ªä¸åŒéƒ¨åˆ†ã€‚å†…æ ¸è™šæ‹Ÿåœ°å€çš„范围很大:没有足够的真实 内å˜æ¥æ”¯æŒå†…æ ¸å¯ä»¥è®¿é—®çš„æ¯ä¸ªåœ°å€çš„真实影ååŒºåŸŸã€‚å› æ¤ï¼ŒKASANåªä¸ºåœ°å€ç©ºé—´çš„æŸäº› éƒ¨åˆ†æ˜ å°„çœŸå®žçš„å½±å。 默认行为 ~~~~~~~~ 默认情况下,体系结构仅将实际内å˜æ˜ å°„åˆ°ç”¨äºŽçº¿æ€§æ˜ å°„çš„é˜´å½±åŒºåŸŸï¼ˆä»¥åŠå¯èƒ½çš„其他 å°åŒºåŸŸï¼‰ã€‚对于所有其他区域 —— 例如vmallocå’Œvmemmap空间 —— 一个åªè¯»é¡µé¢è¢«æ˜ å°„ 到阴影区域上。这个åªè¯»çš„å½±å页é¢å£°æ˜Žæ‰€æœ‰å†…å˜è®¿é—®éƒ½æ˜¯å…许的。 这给模å—带æ¥äº†ä¸€ä¸ªé—®é¢˜ï¼šå®ƒä»¬ä¸å˜åœ¨äºŽçº¿æ€§æ˜ å°„ä¸ï¼Œè€Œæ˜¯å˜åœ¨äºŽä¸“用的模å—空间ä¸ã€‚ 通过连接模å—分é…器,KASANä¸´æ—¶æ˜ å°„çœŸå®žçš„å½±å内å˜ä»¥è¦†ç›–它们。例如,这å…许检测 对模å—全局å˜é‡çš„æ— æ•ˆè®¿é—®ã€‚ è¿™ä¹Ÿé€ æˆäº†ä¸Ž ``VMAP_STACK`` çš„ä¸å…¼å®¹ï¼šå¦‚æžœå †æ ˆä½äºŽvmalloc空间ä¸ï¼Œå®ƒå°†è¢«åˆ†é… åªè¯»é¡µé¢çš„å½±å内å˜ï¼Œå¹¶ä¸”å†…æ ¸åœ¨å°è¯•ä¸ºå †æ ˆå˜é‡è®¾ç½®å½±åæ•°æ®æ—¶ä¼šå‡ºé”™ã€‚ CONFIG_KASAN_VMALLOC ~~~~~~~~~~~~~~~~~~~~ 使用 ``CONFIG_KASAN_VMALLOC`` ,KASANå¯ä»¥ä»¥æ›´å¤§çš„内å˜ä½¿ç”¨ä¸ºä»£ä»·è¦†ç›–vmalloc 空间。目å‰ï¼Œè¿™åœ¨arm64ã€x86ã€riscvã€s390å’Œpowerpc上å—支æŒã€‚ 这通过连接到vmallocå’Œvmap并动æ€åˆ†é…真实的影å内å˜æ¥æ”¯æŒæ˜ 射。 vmalloc空间ä¸çš„å¤§å¤šæ•°æ˜ å°„éƒ½å¾ˆå°ï¼Œéœ€è¦ä¸åˆ°ä¸€æ•´é¡µçš„é˜´å½±ç©ºé—´ã€‚å› æ¤ï¼Œä¸ºæ¯ä¸ªæ˜ å°„ 分é…一个完整的影å页é¢å°†æ˜¯ä¸€ç§æµªè´¹ã€‚æ¤å¤–,为了确ä¿ä¸åŒçš„æ˜ å°„ä½¿ç”¨ä¸åŒçš„å½±å 页é¢ï¼Œæ˜ 射必须与 ``KASAN_GRANULE_SIZE * PAGE_SIZE`` 对é½ã€‚ 相å,KASANè·¨å¤šä¸ªæ˜ å°„å…±äº«åŽå¤‡ç©ºé—´ã€‚当vmalloc空间ä¸çš„æ˜ å°„ä½¿ç”¨å½±å区域的特定 页é¢æ—¶ï¼Œå®ƒä¼šåˆ†é…一个åŽå¤‡é¡µé¢ã€‚æ¤é¡µé¢ç¨åŽå¯ä»¥ç”±å…¶ä»–vmallocæ˜ å°„å…±äº«ã€‚ KASAN连接到vmap基础架构以懒清ç†æœªä½¿ç”¨çš„å½±å内å˜ã€‚ 为了é¿å…交æ¢æ˜ 射的困难,KASAN预测覆盖vmalloc空间的阴影区域部分将ä¸ä¼šè¢«æ—©æœŸ 的阴影页é¢è¦†ç›–,但是将ä¸ä¼šè¢«æ˜ 射。这将需è¦æ›´æ”¹ç‰¹å®šäºŽarch的代ç 。 è¿™å…许在x86ä¸Šæ”¯æŒ ``VMAP_STACK`` ,并且å¯ä»¥ç®€åŒ–对没有固定模å—区域的架构的支æŒã€‚ 对于开å‘者 ---------- 忽略访问 ~~~~~~~~ 软件KASAN模å¼ä½¿ç”¨ç¼–译器æ’æ¡©æ¥æ’入有效性检查。æ¤ç±»æ£€æµ‹å¯èƒ½ä¸Žå†…æ ¸çš„æŸäº›éƒ¨åˆ† ä¸å…¼å®¹ï¼Œå› æ¤éœ€è¦ç¦ç”¨ã€‚ å†…æ ¸çš„å…¶ä»–éƒ¨åˆ†å¯èƒ½ä¼šè®¿é—®å·²åˆ†é…对象的元数æ®ã€‚通常,KASAN会检测并报告æ¤ç±»è®¿é—®ï¼Œ 但在æŸäº›æƒ…况下(例如,在内å˜åˆ†é…器ä¸ï¼‰ï¼Œè¿™äº›è®¿é—®æ˜¯æœ‰æ•ˆçš„。 对于软件KASAN模å¼ï¼Œè¦ç¦ç”¨ç‰¹å®šæ–‡ä»¶æˆ–目录的检测,请将 ``KASAN_SANITIZE`` æ·»åŠ åˆ°ç›¸åº”çš„å†…æ ¸Makefileä¸: - 对于å•ä¸ªæ–‡ä»¶(例如,main.o):: KASAN_SANITIZE_main.o := n - 对于一个目录下的所有文件:: KASAN_SANITIZE := n 对于软件KASAN模å¼ï¼Œè¦åœ¨æ¯ä¸ªå‡½æ•°çš„基础上ç¦ç”¨æ£€æµ‹ï¼Œè¯·ä½¿ç”¨KASAN特定的 ``__no_sanitize_address`` 函数属性或通用的 ``noinstr`` 。 请注æ„,ç¦ç”¨ç¼–译器æ’桩(基于æ¯ä¸ªæ–‡ä»¶æˆ–æ¯ä¸ªå‡½æ•°ï¼‰ä¼šä½¿KASAN忽略在软件KASANæ¨¡å¼ çš„ä»£ç ä¸ç›´æŽ¥å‘生的访问。当访问是间接å‘生的(通过调用检测函数)或使用没有编译器 æ’æ¡©çš„åŸºäºŽç¡¬ä»¶æ ‡ç¾çš„模å¼æ—¶ï¼Œå®ƒæ²¡æœ‰å¸®åŠ©ã€‚ 对于软件KASAN模å¼ï¼Œè¦åœ¨å½“å‰ä»»åŠ¡çš„ä¸€éƒ¨åˆ†å†…æ ¸ä»£ç ä¸ç¦ç”¨KASAN报告,请使用 ``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是å¦æ£å¸¸å·¥ä½œå¹¶å¯ä»¥æ£€æµ‹æŸäº›ç±»åž‹çš„内å˜æŸå。 测试由两部分组æˆ: 1. 与KUnit测试框架集æˆçš„测试。使用 ``CONFIG_KASAN_KUNIT_TEST`` å¯ç”¨ã€‚ 这些测试å¯ä»¥é€šè¿‡å‡ ç§ä¸åŒçš„æ–¹å¼è‡ªåŠ¨è¿è¡Œå’Œéƒ¨åˆ†éªŒè¯ï¼›è¯·å‚阅下é¢çš„说明。 2. 与KUnitä¸å…¼å®¹çš„测试。使用 ``CONFIG_KASAN_MODULE_TEST`` å¯ç”¨å¹¶ä¸”åªèƒ½ä½œä¸ºæ¨¡å— è¿è¡Œã€‚这些测试åªèƒ½é€šè¿‡åŠ è½½å†…æ ¸æ¨¡å—å¹¶æ£€æŸ¥å†…æ ¸æ—¥å¿—ä»¥èŽ·å–KASAN报告æ¥æ‰‹åŠ¨éªŒè¯ã€‚ 如果检测到错误,æ¯ä¸ªKUnit兼容的KASAN测试都会打å°å¤šä¸ªKASAN报告之一,然åŽæµ‹è¯•æ‰“å° å…¶ç¼–å·å’ŒçŠ¶æ€ã€‚ 当测试通过:: ok 28 - kmalloc_double_kzfree 当由于 ``kmalloc`` 失败而导致测试失败时:: # kmalloc_large_oob_right: ASSERTION FAILED at lib/test_kasan.c:163 Expected ptr is not null, but is not ok 4 - kmalloc_large_oob_right 当由于缺少KASAN报告而导致测试失败时:: # 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测试的累积状æ€ã€‚æˆåŠŸ:: ok 1 - kasan 或者,如果其ä¸ä¸€é¡¹æµ‹è¯•å¤±è´¥:: not ok 1 - kasan æœ‰å‡ ç§æ–¹æ³•å¯ä»¥è¿è¡Œä¸ŽKUnit兼容的KASAN测试。 1. å¯åŠ è½½æ¨¡å— å¯ç”¨ ``CONFIG_KUNIT`` åŽï¼ŒKASAN-KUnit测试å¯ä»¥æž„建为å¯åŠ 载模å—,并通过使用 ``insmod`` 或 ``modprobe`` åŠ è½½ ``test_kasan.ko`` æ¥è¿è¡Œã€‚ 2. 内置 通过内置 ``CONFIG_KUNIT`` ,也å¯ä»¥å†…ç½®KASAN-KUnit测试。在这ç§æƒ…况下, 测试将在å¯åŠ¨æ—¶ä½œä¸ºåŽæœŸåˆå§‹åŒ–调用è¿è¡Œã€‚ 3. 使用kunit_tool 通过内置 ``CONFIG_KUNIT`` å’Œ ``CONFIG_KASAN_KUNIT_TEST`` ,还å¯ä»¥ä½¿ç”¨ ``kunit_tool`` 以更易读的方å¼æŸ¥çœ‹KUnit测试结果。这ä¸ä¼šæ‰“å°é€šè¿‡æµ‹è¯• çš„KASAN报告。有关 ``kunit_tool`` 更多最新信æ¯ï¼Œè¯·å‚阅 `KUnit文档 <https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html>`_ 。 .. _KUnit: https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html