ILD

初识kasan
作者:Yuan Jianpeng 邮箱:yuanjp89@163.com
发布时间:2023-8-1 站点:Inside Linux Development

kasan (Kernel Address Sanitizer)是内核的内存检查工具,用来定位内核memory corruption等问题。后面还有一个kfence工具,算是一个后起之秀。


kasan的原理是,每8个字节,使用一个字节,来表示这个8字节内存的状态。然后通过gcc编译选项,生成指令,在每个内存读写的时候,进行检查。判断是否是非法的读写访问。内核一起来的时候,kasan就会保留1/8的内存,因此在内存紧张的设备上,可能kasan跑不起来。


为了支持越界写检查,kasan还修改slab,在分配的内存后面添加red zone。写入red zone意味着越界写。


开启内核KASAN支持:

Kernel hacking  --->

    Memory Debugging  --->

        [*] KASAN: runtime memory debugger  --->



编写一个test.ko,他分配10个字节,然后写第20个字节,构造一个越界写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
 
static void out_of_bound_write(void)
{
        char *a;
 
        a = kmalloc(10, GFP_KERNEL);
        a[20] = 0;
}
 
static int __init test_init(void)
{
        /*
         * Temporarily enable multi-shot mode. Otherwise, KASAN would only
         * report the first detected bug and panic the kernel if panic_on_warn
         * is enabled.
         */
        bool multishot = kasan_save_enable_multi_shot();
 
        out_of_bound_write();
 
        kasan_restore_multi_shot(multishot);
        return -1;
}
 
static void __exit test_exit(void)
{
}
 
module_init(test_init);
module_exit(test_exit);
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jianpeng Yuan");
MODULE_DESCRIPTION("test module");


将ko上传到设备,然后安装 insmod ./test.ko,可以看到kasan成功的检测了到slab out of bound write


[   36.876948] ==================================================================

[   36.877022] BUG: KASAN: slab-out-of-bounds in test_init+0x40/0x1000 [test]

[   36.883101] Write of size 1 at addr 8612f094 by task insmod/193

[   36.889957]

[   36.895772] CPU: 1 PID: 193 Comm: insmod Tainted: G           O      5.15.38+ #2

[   36.897510] Hardware name: Generic DT based system

[   36.904895] [<81314f74>] (unwind_backtrace) from [<8130ea14>] (show_stack+0x10/0x14)

[   36.909494] [<8130ea14>] (show_stack) from [<81c725c0>] (dump_stack_lvl+0x40/0x4c)

[   36.917395] [<81c725c0>] (dump_stack_lvl) from [<81c6fa58>] (print_address_description.constprop.0+0x5c/0x2bc)

[   36.924773] [<81c6fa58>] (print_address_description.constprop.0) from [<8153eaf0>] (kasan_report+0x1b4/0x1d0)

[   36.934756] [<8153eaf0>] (kasan_report) from [<7f156040>] (test_init+0x40/0x1000 [test])

[   36.944739] [<7f156040>] (test_init [test]) from [<813027dc>] (do_one_initcall+0xbc/0x3d4)

[   36.952897] [<813027dc>] (do_one_initcall) from [<81415918>] (do_init_module+0xbc/0x328)

[   36.960972] [<81415918>] (do_init_module) from [<81419514>] (load_module+0x38b4/0x3d90)

[   36.969216] [<81419514>] (load_module) from [<81419d18>] (sys_finit_module+0x124/0x170)

[   36.976942] [<81419d18>] (sys_finit_module) from [<81300060>] (ret_fast_syscall+0x0/0x48)

[   36.984926] Exception stack(0x8666bfa8 to 0x8666bff0)

[   36.993267] bfa0:                   000fc190 ffffffff 00000003 000fc190 00000000 6e75df7e

[   36.998307] bfc0: 000fc190 ffffffff 00000077 0000017b 0001caf4 00000000 00000000 000fbb74

[   37.006462] bfe0: 6e75dcb8 6e75dca8 00034620 66c95820

[   37.014613]

[   37.019640] Allocated by task 193:

[   37.021205]  test_init+0x24/0x1000 [test]

[   37.024416]  do_one_initcall+0xbc/0x3d4

[   37.028495]  do_init_module+0xbc/0x328

[   37.032141]  load_module+0x38b4/0x3d90

[   37.035961]  sys_finit_module+0x124/0x170

[   37.039694]  ret_fast_syscall+0x0/0x48

[   37.043773]  0x6e75dca8

[   37.047416]

[   37.049760] The buggy address belongs to the object at 8612f080

[   37.049760]  which belongs to the cache kmalloc-64 of size 64

[   37.051509] The buggy address is located 20 bytes inside of

[   37.051509]  64-byte region [8612f080, 8612f0c0)

[   37.063053] The buggy address belongs to the page:

[   37.073290] page:3b0e1a95 refcount:1 mapcount:0 mapping:00000000 index:0x0 pfn:0x4612f

[   37.077894] flags: 0x200(slab|zone=0)

[   37.085810] raw: 00000200 00000000 00000122 80801200 00000000 80200020 ffffffff 00000001

[   37.089526] page dumped because: kasan: bad access detected

[   37.097682]

[   37.102971] Memory state around the buggy address:

[   37.104719]  8612ef80: fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc fc

[   37.109321]  8612f000: 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc

[   37.115830] >8612f080: 00 02 fc fc fc fc fc fc fc fc fc fc fc fc fc fc

[   37.122335]                  ^

[   37.128848]  8612f100: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc

[   37.131890]  8612f180: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc

[   37.138394] ==================================================================



参考:

The Kernel Address Sanitizer (KASAN)

https://www.kernel.org/doc/html/v4.14/dev-tools/kasan.html


KASAN: WHAT IS IT? HOW DOES IT WORK? AND WHAT ARE THE STRANGE NUMBERS AT THE END?

https://www.starlab.io/blog/kasan-what-is-it-how-does-it-work-and-what-are-the-strange-numbers-at-the-end


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.