编译内核启用KASan动态检测内核内存错误功能(ubuntu16.04 4.4.0内核编译升级到linux-4.4.252版本)

目录

一、编译内核并配置支持KAsan

1、下载源码

2、安装编译内核必须的库

3、清理之前内核编译生成及相关配置

4、配置内核参数

5、开始编译

6、模块(驱动)安装

7、安装新编译的内核

8、修改内核启动顺序

9、reboot

二、编写测试内核模块

1、测试代码编写

2、编写Makefile文件

3、编译内核模块

4、insmod插入内核模块

5、dmesg -Tw查看系统内核日志


KASan(kernel address sanitizer)是一个内核态的动态内存错误检测器,提供了强大的内存错误(out-of-bound and use-after-free)检测功能:

  • 缓冲区溢出 
    ①、堆内存溢出
    ②、栈上内存溢出
    ③、全局区缓存溢出

  • 悬空指针
    ①、使用释放后的堆上内存
    ②、使用返回的栈上内存
    ③、使用退出作用域的变量

  • ...

由于KASan在内核版本V4.0后才加入,而且内核编译时默认是不启用KASan的,所以需要重新编译配置内核才能启用该功能(gcc版本要求5.0及以上才完全支持)。

本文实验环境:

root@ubuntu:~# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.6 LTS
Release:        16.04
Codename:       xenial
root@ubuntu:~# 
root@ubuntu:~# uname -r
4.4.0-142-generic
root@ubuntu:~# 

内容提要:

①先将ubuntu16.04的4.4.0内核编译升级到linux-4.4.252版本;

②编写一个简单的内核模块看下kasan的强大检测功能。

一、编译内核并配置支持KAsan

1、下载源码

Linux官网下载内核源码,我这里选择了linux-4.4.252源码

下载完成后,解压到/usr/src下。

root@ubuntu:~# cd /usr/src/
root@ubuntu:/usr/src# wget https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/linux-4.4.252.tar.gz
root@ubuntu:/usr/src# tar xf linux-4.4.252.tar.gz
root@ubuntu:/usr/src# cd linux-4.4.252

2、安装编译内核必须的库

apt-get install libssl-dev build-essential openssl -y
apt-get install zlibc minizip libidn11-dev libidn11 -y

apt-get install libncurses5-dev

3、清理之前内核编译生成及相关配置

这里是为下面全新编译内核做准备:

root@ubuntu:/usr/src/linux-4.4.252# make mrproper 
  CLEAN   scripts/basic
  CLEAN   scripts/kconfig
  CLEAN   include/config include/generated
root@ubuntu:/usr/src/linux-4.4.252# make clean
root@ubuntu:/usr/src/linux-4.4.252# 

4、配置内核参数

root@ubuntu:/usr/src/linux-4.4.252# make menuconfig

依次选择Kernel hacking > Memory Debugging,然后配置内存debug选项,这里我把大部分debug选项都选中了:

其中,KASan选项中Instrumentation type选inline的:

配置完成后,exit退出,最后选择yes保存配置项。

5、开始编译

make -j4

内核编译比较耗时,一般都要半个小时到几个小时(取决于机器性能),为了加快内核编译速度,这里我启用4个线程编译内核,你可以根据自己机器的cpu核数进行调整(lscpu命令可以查看cpu核数)。

6、模块(驱动)安装

root@ubuntu:/usr/src/linux-4.4.252# make modules_install 

7、安装新编译的内核

root@ubuntu:/usr/src/linux-4.4.252# make install 
sh ./arch/x86/boot/install.sh 4.4.252 arch/x86/boot/bzImage \
        System.map "/boot"
run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 4.4.252 /boot/vmlinuz-4.4.252
run-parts: executing /etc/kernel/postinst.d/initramfs-tools 4.4.252 /boot/vmlinuz-4.4.252
update-initramfs: Generating /boot/initrd.img-4.4.252
run-parts: executing /etc/kernel/postinst.d/zz-update-grub 4.4.252 /boot/vmlinuz-4.4.252
Generating grub configuration file ...
Warning: Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.
Found linux image: /boot/vmlinuz-4.4.252
Found initrd image: /boot/initrd.img-4.4.252
Found linux image: /boot/vmlinuz-4.4.0-171-generic
Found initrd image: /boot/initrd.img-4.4.0-171-generic
Found linux image: /boot/vmlinuz-4.4.0-170-generic
Found initrd image: /boot/initrd.img-4.4.0-170-generic
Found linux image: /boot/vmlinuz-4.4.0-142-generic
Found initrd image: /boot/initrd.img-4.4.0-142-generic
done

8、修改内核启动顺序

root@ubuntu:~# grep menuentry /boot/grub/grub.cfg
if [ x"${feature_menuentry_id}" = xy ]; then
  menuentry_id_option="--id"
  menuentry_id_option=""
export menuentry_id_option
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
submenu 'Advanced options for Ubuntu' $menuentry_id_option 'gnulinux-advanced-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
        menuentry 'Ubuntu, with Linux 4.4.252' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.252-advanced-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
        menuentry 'Ubuntu, with Linux 4.4.252 (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.252-recovery-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
        menuentry 'Ubuntu, with Linux 4.4.0-171-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-171-generic-advanced-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
        menuentry 'Ubuntu, with Linux 4.4.0-171-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-171-generic-recovery-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
        menuentry 'Ubuntu, with Linux 4.4.0-170-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-170-generic-advanced-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
        menuentry 'Ubuntu, with Linux 4.4.0-170-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-170-generic-recovery-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
        menuentry 'Ubuntu, with Linux 4.4.0-142-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-142-generic-advanced-39f6e796-6e9e-41ae-89db-fade0f403ad4' {
        menuentry 'Ubuntu, with Linux 4.4.0-142-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-142-generic-recovery-39f6e796-6e9e-41ae-89db-fade0f403ad4' {

修改配置:

root@ubuntu:~# vi /etc/default/grub 

修改/etc/default/grub文件里GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 4.4.252",红色部分即为上面查找到的新生成的menuentry值。

然后执行update-grub命令,使改动生效:

root@ubuntu:~# update-grub
Generating grub configuration file ...
Warning: Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.
Found linux image: /boot/vmlinuz-4.4.252
Found initrd image: /boot/initrd.img-4.4.252
Found linux image: /boot/vmlinuz-4.4.0-171-generic
Found initrd image: /boot/initrd.img-4.4.0-171-generic
Found linux image: /boot/vmlinuz-4.4.0-170-generic
Found initrd image: /boot/initrd.img-4.4.0-170-generic
Found linux image: /boot/vmlinuz-4.4.0-142-generic
Found initrd image: /boot/initrd.img-4.4.0-142-generic
done
root@ubuntu:~# 

9、reboot

重启之后,可以查看验证:

root@ubuntu:~# uname -r
4.4.252
root@ubuntu:~# 
root@ubuntu:~# grep -nr KASAN /boot/config-4.4.252 
38:CONFIG_KASAN_SHADOW_OFFSET=0xdffffc0000000000
7901:CONFIG_HAVE_ARCH_KASAN=y
7902:CONFIG_KASAN=y
7903:# CONFIG_KASAN_OUTLINE is not set
7904:CONFIG_KASAN_INLINE=y
7905:CONFIG_TEST_KASAN=m

可以看到,KASan相关的配置都已经启用了。

二、编写测试内核模块

1、测试代码编写

命名为my_lkm.c文件:

#include <linux/module.h>
#include <linux/kallsyms.h>
#include <asm/uaccess.h>
#include <linux/syscalls.h>
#include <linux/kernel.h> // __FUNCTION__
#include <linux/slab.h> // kmalloc kfree

MODULE_LICENSE("GPL");

static int __init test_init(void) 
{ 
    char *ptr; 
    size_t size = 124; 

    printk("out-of-bounds to right\n"); 
    ptr = kmalloc(size, GFP_KERNEL); 
    if (!ptr) { 
        printk(KERN_ERR "Allocation failed\n"); 
        return -1; 
    } 
    printk("ptr address: %p\n", ptr); 

    ptr[size] = 'x'; 
    printk("ptr[size] address: %p\n", ptr + size); 

    kfree(ptr);
    return 0;
}
 

static void __exit test_exit(void)
{
    printk("%s removed.\n",__func__);
}

module_init(test_init);
module_exit(test_exit);

上述代码中,我们从slab中申请了一个指向124个字节大小的内存空间指针,然后用数组形式访问其第125个字节空间内容,这里故意越界访问,这样kasan会报slab-out-of-bounds错误,见下面系统日志输出。

2、编写Makefile文件

vi Makefile

内容如下:

​
obj-m += my_test_lkm.o
my_test_lkm-objs := my_lkm.o

EXTRA_CFLAGS += -g -Wall

all:
	make -C /usr/src/linux-4.4.252/ M=$(PWD) modules
	 
clean:
	make -C /usr/src/linux-4.4.252/ M=$(PWD) clean

​

3、编译内核模块

root@ubuntu:/home/test_ko/lkm-test05# make
make -C /usr/src/linux-4.4.252/ M=/home/test_ko/lkm-test05 modules
make[1]: Entering directory '/usr/src/linux-4.4.252'
  CC [M]  /home/test_ko/lkm-test05/my_lkm.o
  LD [M]  /home/test_ko/lkm-test05/my_test_lkm.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/test_ko/lkm-test05/my_test_lkm.mod.o
  LD [M]  /home/test_ko/lkm-test05/my_test_lkm.ko
make[1]: Leaving directory '/usr/src/linux-4.4.252'
root@ubuntu:/home/test_ko/lkm-test05# 

4、insmod插入内核模块

insmod my_test_lkm.ko

5、dmesg -Tw查看系统内核日志

可以看到系统内核日志中,KASan报BUG: KASAN: slab-out-of-bounds in test_init+0xa2/0x1000 ,并且下面详细列出了在哪里申请的(Allocated)、哪里释放的(Freed)及整个调用链的详细信息:

[Tue Jan 19 18:27:29 2021] out-of-bounds to right
[Tue Jan 19 18:27:29 2021] ptr address: ffff8800badbd910
[Tue Jan 19 18:27:29 2021] ==================================================================
[Tue Jan 19 18:27:29 2021] BUG: KASAN: slab-out-of-bounds in test_init+0xa2/0x1000 [my_test_lkm] at addr ffff8800badbd98c
[Tue Jan 19 18:27:29 2021] Write of size 1 by task insmod/100870
[Tue Jan 19 18:27:29 2021] =============================================================================
[Tue Jan 19 18:27:29 2021] BUG kmalloc-128 (Tainted: G    B      OE  ): kasan: bad access detected
[Tue Jan 19 18:27:29 2021] -----------------------------------------------------------------------------

[Tue Jan 19 18:27:29 2021] INFO: Allocated in test_init+0x4c/0x1000 [my_test_lkm] age=4 cpu=0 pid=100870
[Tue Jan 19 18:27:29 2021]      ___slab_alloc+0x4d9/0x550
[Tue Jan 19 18:27:29 2021]      __slab_alloc+0x20/0x40
[Tue Jan 19 18:27:29 2021]      kmem_cache_alloc_trace+0x24c/0x2e0
[Tue Jan 19 18:27:29 2021]      test_init+0x4c/0x1000 [my_test_lkm]
[Tue Jan 19 18:27:29 2021]      do_one_initcall+0x143/0x300
[Tue Jan 19 18:27:29 2021]      do_init_module+0x1d9/0x4de
[Tue Jan 19 18:27:29 2021]      load_module+0x6a4f/0xa160
[Tue Jan 19 18:27:29 2021]      SYSC_finit_module+0x126/0x160
[Tue Jan 19 18:27:29 2021]      SyS_finit_module+0xe/0x10
[Tue Jan 19 18:27:29 2021]      entry_SYSCALL_64_fastpath+0x22/0x9e
[Tue Jan 19 18:27:29 2021] INFO: Freed in load_elf_binary+0x220/0x4480 age=14729 cpu=0 pid=100293
[Tue Jan 19 18:27:29 2021]      __slab_free+0x1bc/0x300
[Tue Jan 19 18:27:29 2021]      kfree+0x106/0x1e0
[Tue Jan 19 18:27:29 2021]      load_elf_binary+0x220/0x4480
[Tue Jan 19 18:27:29 2021]      search_binary_handler+0x156/0x430
[Tue Jan 19 18:27:29 2021]      do_execveat_common.isra.31+0x1025/0x1ae0
[Tue Jan 19 18:27:29 2021]      SyS_execve+0x3a/0x50
[Tue Jan 19 18:27:29 2021]      return_from_execve+0x0/0x23
[Tue Jan 19 18:27:29 2021] INFO: Slab 0xffffea0002eb6e00 objects=71 used=30 fp=0xffff8800badbb738 flags=0x1ffff8000004080
[Tue Jan 19 18:27:29 2021] INFO: Object 0xffff8800badbd910 @offset=22800 fp=0xffff8800badb9728

[Tue Jan 19 18:27:29 2021] Bytes b4 ffff8800badbd900: 19 37 d1 00 01 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a  .7......ZZZZZZZZ
[Tue Jan 19 18:27:29 2021] Object ffff8800badbd910: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[Tue Jan 19 18:27:29 2021] Object ffff8800badbd920: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[Tue Jan 19 18:27:29 2021] Object ffff8800badbd930: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[Tue Jan 19 18:27:29 2021] Object ffff8800badbd940: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[Tue Jan 19 18:27:29 2021] Object ffff8800badbd950: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[Tue Jan 19 18:27:29 2021] Object ffff8800badbd960: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[Tue Jan 19 18:27:29 2021] Object ffff8800badbd970: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b  kkkkkkkkkkkkkkkk
[Tue Jan 19 18:27:29 2021] Object ffff8800badbd980: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5  kkkkkkkkkkkkkkk.
[Tue Jan 19 18:27:29 2021] Redzone ffff8800badbd990: cc cc cc cc cc cc cc cc                          ........
[Tue Jan 19 18:27:29 2021] Padding ffff8800badbdad0: 5a 5a 5a 5a 5a 5a 5a 5a                          ZZZZZZZZ
[Tue Jan 19 18:27:29 2021] CPU: 0 PID: 100870 Comm: insmod Tainted: G    B      OE   4.4.252 #1
[Tue Jan 19 18:27:29 2021] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/29/2019
[Tue Jan 19 18:27:29 2021]  0000000000000000 41692362580668d4 ffff8800a1287898 ffffffff82988c2f
[Tue Jan 19 18:27:29 2021]  ffff88011840f580 ffff8800badbd910 ffff8800a12878c8 ffffffff81585cc9
[Tue Jan 19 18:27:29 2021]  ffff88011840f580 ffffea0002eb6e00 ffff8800badbd910 0000000000000001
[Tue Jan 19 18:27:29 2021] Call Trace:
[Tue Jan 19 18:27:29 2021]  [<ffffffff82988c2f>] dump_stack+0x6d/0x8b
[Tue Jan 19 18:27:29 2021]  [<ffffffff81585cc9>] print_trailer+0xf9/0x150
[Tue Jan 19 18:27:29 2021]  [<ffffffff8158cda4>] object_err+0x34/0x40
[Tue Jan 19 18:27:29 2021]  [<ffffffff8158f5ad>] kasan_report.part.2+0x21d/0x520
[Tue Jan 19 18:27:29 2021]  [<ffffffffc0a500a2>] ? test_init+0xa2/0x1000 [my_test_lkm]
[Tue Jan 19 18:27:29 2021]  [<ffffffff81589fb0>] ? kmem_cache_alloc_trace+0x120/0x2e0
[Tue Jan 19 18:27:29 2021]  [<ffffffffc0a50000>] ? 0xffffffffc0a50000
[Tue Jan 19 18:27:29 2021]  [<ffffffff8158f9d1>] __asan_report_store1_noabort+0x31/0x40
[Tue Jan 19 18:27:29 2021]  [<ffffffffc0a500a2>] test_init+0xa2/0x1000 [my_test_lkm]
[Tue Jan 19 18:27:29 2021]  [<ffffffff810021b3>] do_one_initcall+0x143/0x300
[Tue Jan 19 18:27:29 2021]  [<ffffffff81002070>] ? try_to_run_init_process+0x40/0x40
[Tue Jan 19 18:27:29 2021]  [<ffffffff8158eca6>] ? kasan_unpoison_shadow+0x36/0x50
[Tue Jan 19 18:27:29 2021]  [<ffffffff8158eca6>] ? kasan_unpoison_shadow+0x36/0x50
[Tue Jan 19 18:27:29 2021]  [<ffffffff8158ed1e>] ? kasan_kmalloc+0x5e/0x70
[Tue Jan 19 18:27:29 2021]  [<ffffffff8158eca6>] ? kasan_unpoison_shadow+0x36/0x50
[Tue Jan 19 18:27:29 2021]  [<ffffffff8158edb7>] ? __asan_register_globals+0x87/0xa0
[Tue Jan 19 18:27:29 2021]  [<ffffffff82985bf4>] do_init_module+0x1d9/0x4de
[Tue Jan 19 18:27:29 2021]  [<ffffffff812fc3df>] load_module+0x6a4f/0xa160
[Tue Jan 19 18:27:29 2021]  [<ffffffff812f0c00>] ? m_show+0x4b0/0x4b0
[Tue Jan 19 18:27:29 2021]  [<ffffffff812f5990>] ? module_frob_arch_sections+0x20/0x20
[Tue Jan 19 18:27:29 2021]  [<ffffffff815eeedb>] ? kernel_read+0xeb/0x1a0
[Tue Jan 19 18:27:29 2021]  [<ffffffff815eedf0>] ? open_exec+0x50/0x50
[Tue Jan 19 18:27:29 2021]  [<ffffffff812f10dd>] ? copy_module_from_fd.isra.50+0x1dd/0x2f0
[Tue Jan 19 18:27:29 2021]  [<ffffffff812ffe26>] SYSC_finit_module+0x126/0x160
[Tue Jan 19 18:27:29 2021]  [<ffffffff812ffd00>] ? SYSC_init_module+0x210/0x210
[Tue Jan 19 18:27:29 2021]  [<ffffffff812ffe7e>] SyS_finit_module+0xe/0x10
[Tue Jan 19 18:27:29 2021]  [<ffffffff829ab5e5>] entry_SYSCALL_64_fastpath+0x22/0x9e
[Tue Jan 19 18:27:29 2021] Memory state around the buggy address:
[Tue Jan 19 18:27:29 2021]  ffff8800badbd880: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[Tue Jan 19 18:27:29 2021]  ffff8800badbd900: fc fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[Tue Jan 19 18:27:29 2021] >ffff8800badbd980: 00 04 fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[Tue Jan 19 18:27:29 2021]                       ^
[Tue Jan 19 18:27:29 2021]  ffff8800badbda00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[Tue Jan 19 18:27:29 2021]  ffff8800badbda80: fc fc fc fc fc fc fc fc fc fc fc 00 00 00 00 00
[Tue Jan 19 18:27:29 2021] ==================================================================
[Tue Jan 19 18:27:29 2021] ptr[size] address: ffff8800badbd98c

本文已同步至我的微信公众号这篇文章:使用KASan动态检测内核态内存错误(基于Ubuntu 16.04)

欢迎关注我的微信公众号大胖聊编程,也可以加好友一起交流学习。

参考链接:

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

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值