概述
一、简介:
Kasan 是 Kernel Address Sanitizer 的缩写,它是一个动态检测内存错误的工具,主要功能是检查内存越界访问和使用已释放的内存等问题。KASAN可以检测的内存异常包括:slab-out-of-bounds/user-after-free/stack-out-of-bounds/global-out-of-bounds等。
(1)环境要求:
GCC 5.0或者以上的编译器;
(2)打开方法:
CONFIG_KASAN=y
CONFIG_KASAN_OUTLINE=y(性能会变差)或CONFIG_KASAN_INLINE=y
如某些文件或者目录不想加入KASAN的检测,可以做如下处理:
在对应的Makefile里添加(文件:xxx.c):
KASAN_SANITIZE_xxx.o := n
在对应的Makefile里添加:
KASAN_SANITIZE := n
(3)相关概念
如下图是8个字节内存映射1个字节shadow memory,(部分内核可能是16:1的关系,后面的例程就是16:1),这样8字节的内存就会牺牲1字节的用于标记readzone,这样会导致性能的部分下降,造成系统卡顿。下图中,当8个字节全部可用时,这块shadow memory会标记位0x00,7个字节可用时会标记位0x07 ......;
部分其他的值代表如下:
在内存相关的操作时,当打开KASAN时,编译器自动插入检查代码:
*address = ...; // or: ... = *address;// 操作某块地址
shadow_address = MemToShadow(address);
if (ShadowIsPoisoned(shadow_address)) { //对该块地址进行检查
ReportError(address, kAccessSize, kIsWrite); //越界或者其他异常报错
}
*address = ...; // or: ... = *address;//无异常继续进行操作
二、实例:
(1)slab-out-of-bounds越界检测:
在前文创建sys节点的基础上,对cat调用的的show函数修改如下:
static ssize_t hello_test_show(struct device *dev, struct device_attribute *attr, char *buf)
{
size_t size = 21;
char *ptr = NULL;
printk("hello_test %s,%dn",__FUNCTION__,__LINE__);
ptr = kmalloc(size, GFP_KERNEL); //申请21bit字节可用的内存
if(!ptr){
pr_err("Allocation failed! n");
return -1;
}
ptr[size + 1] = 'X';//给30 + 1大小的内存写X,实际越界2字节
kfree(ptr);
return 0;
}
当cat /sys/bus/platform/drivers/hello_test/odm:hello_test/hello_test,会产生越界异常,这是KASAN的机制会捕捉到,并产生KE异常,解析KE的DB文件,如下看到如下堆栈异常:
[ 101.291091] (3)[5074:cat]hello_test hello_test_show,16
[ 101.291131] -(3)[5074:cat]==================================================================
[ 101.291163] -(3)[5074:cat]BUG: KASAN: slab-out-of-bounds in hello_test_show+0x58/0x88 at addr ffffffdabc0a2a96
[ 101.291175] -(3)[5074:cat]Write of size 1 by task cat/5074
[ 101.291195] -(3)[5074:cat]CPU: 3 PID: 5074 Comm: cat Tainted: G W O 4.9.77+ #16
[ 101.291206] -(3)[5074:cat]Hardware name: MT6761V/WBB (DT)
[ 101.291218] -(3)[5074:cat]Call trace:
[ 101.291239] -(3)[5074:cat][<ffffff8fa848b4e8>] dump_backtrace+0x0/0x358
[ 101.291254] -(3)[5074:cat][<ffffff8fa848b8dc>] show_stack+0x14/0x20
[ 101.291273] -(3)[5074:cat][<ffffff8fa88de118>] dump_stack+0xa8/0xd0
[ 101.291293] -(3)[5074:cat][<ffffff8fa86933c4>] kasan_object_err+0x24/0x80
[ 101.291308] -(3)[5074:cat][<ffffff8fa8693654>] kasan_report.part.1+0x1dc/0x498
[ 101.291323] -(3)[5074:cat][<ffffff8fa8693b98>] qlist_move_cache+0x0/0xc0
[ 101.291338] -(3)[5074:cat][<ffffff8fa8691fe4>] __asan_store1+0x4c/0x58
[ 101.291354] -(3)[5074:cat][<ffffff8fa8ec13a8>] hello_test_show+0x58/0x88
[ 101.291371] -(3)[5074:cat][<ffffff8fa8a12678>] dev_attr_show+0x40/0x88
[ 101.291389] -(3)[5074:cat][<ffffff8fa87549b8>] sysfs_kf_seq_show+0x128/0x1c8
[ 101.291404] -(3)[5074:cat][<ffffff8fa8752720>] kernfs_seq_show+0x80/0x98
[ 101.291421] -(3)[5074:cat][<ffffff8fa86d6fd4>] seq_read+0x14c/0x720
[ 101.291436] -(3)[5074:cat][<ffffff8fa8753774>] kernfs_fop_read+0x1e4/0x280
[ 101.291452] -(3)[5074:cat][<ffffff8fa86a074c>] __vfs_read+0x74/0x1d0
[ 101.291466] -(3)[5074:cat][<ffffff8fa86a1ac0>] vfs_read+0x98/0x188
[ 101.291480] -(3)[5074:cat][<ffffff8fa86a35b0>] SyS_read+0x68/0xe0
[ 101.291496] -(3)[5074:cat][<ffffff8fa8482f70>] el0_svc_naked+0x24/0x28
[ 101.291508] -(3)[5074:cat]Object at ffffffdabc0a2a80, in cache kmalloc-64 size: 64
[ 101.291517] -(3)[5074:cat]Allocated:
......
[ 101.291989] -(3)[5074:cat] ffffffdabc0a2800: fb fb fb fb fc fc fc fc fb fb fb fb fc fc fc fc
[ 101.292003] -(3)[5074:cat] ffffffdabc0a2900: 00 00 00 fc fc fc fc fc 00 00 00 00 fc fc fc fc
[ 101.292016] -(3)[5074:cat]>ffffffdabc0a2a00: fb fb fb fb fc fc fc fc 00 05 fc fc fc fc fc fc
[ 101.292026] -(3)[5074:cat] ^
其中:
0xFC是Redzone标记,如果访问了Redzone区域KASAN就会检测out-of-bounds的发生;
0xFB标记内存是释放的状态。但是不是可用状态;
0x00是可用内存;
此处的shadow memory和可用内存是16:1的 关系,故0x00代表16字节可用,0x05代码5字节可用,故和申请的21字节匹配上。
(2)user-after-free释放后使用:
将代码修改如下,然后cat对应的节点,同样会产生KE的DB文件,
static ssize_t hello_test_show(struct device *dev, struct device_attribute *attr, char *buf)
{
size_t size = 21;
char *ptr = NULL;
printk("hello_test %s,%dn",__FUNCTION__,__LINE__);
ptr = kmalloc(size, GFP_KERNEL);
if(!ptr){
pr_err("Allocation failed! n");
return -1;
}
//ptr[size + 1] = 'X';
kfree(ptr); //提前释放
ptr[size - 1] = 'X'; //释放后对此内存进程赋值写入数据
return 0;
}
log显示如下:
[ 98.979214] (1)[4982:cat]hello_test hello_test_show,16
[ 98.979256] -(1)[4982:cat]==================================================================
[ 98.979284] -(1)[4982:cat]BUG: KASAN: use-after-free in hello_test_show+0x5c/0x88 at addr ffffffe777c16f94
[ 98.979296] -(1)[4982:cat]Write of size 1 by task cat/4982
[ 98.979313] -(1)[4982:cat]CPU: 1 PID: 4982 Comm: cat Tainted: G W O 4.9.77+ #18
[ 98.979324] -(1)[4982:cat]Hardware name: MT6761V/WBB (DT)
[ 98.979334] -(1)[4982:cat]Call trace:
[ 98.979354] -(1)[4982:cat][<ffffffa7baa8b4e8>] dump_backtrace+0x0/0x358
[ 98.979368] -(1)[4982:cat][<ffffffa7baa8b8dc>] show_stack+0x14/0x20
[ 98.979385] -(1)[4982:cat][<ffffffa7baede118>] dump_stack+0xa8/0xd0
[ 98.979402] -(1)[4982:cat][<ffffffa7bac933c4>] kasan_object_err+0x24/0x80
[ 98.979417] -(1)[4982:cat][<ffffffa7bac93654>] kasan_report.part.1+0x1dc/0x498
[ 98.979431] -(1)[4982:cat][<ffffffa7bac93b98>] qlist_move_cache+0x0/0xc0
[ 98.979444] -(1)[4982:cat][<ffffffa7bac91fe4>] __asan_store1+0x4c/0x58
[ 98.979459] -(1)[4982:cat][<ffffffa7bb4c13ac>] hello_test_show+0x5c/0x88
[ 98.979475] -(1)[4982:cat][<ffffffa7bb012678>] dev_attr_show+0x40/0x88
[ 98.979491] -(1)[4982:cat][<ffffffa7bad549b8>] sysfs_kf_seq_show+0x128/0x1c8
[ 98.979506] -(1)[4982:cat][<ffffffa7bad52720>] kernfs_seq_show+0x80/0x98
[ 98.979521] -(1)[4982:cat][<ffffffa7bacd6fd4>] seq_read+0x14c/0x720
[ 98.979534] -(1)[4982:cat][<ffffffa7bad53774>] kernfs_fop_read+0x1e4/0x280
[ 98.979549] -(1)[4982:cat][<ffffffa7baca074c>] __vfs_read+0x74/0x1d0
[ 98.979562] -(1)[4982:cat][<ffffffa7baca1ac0>] vfs_read+0x98/0x188
[ 98.979575] -(1)[4982:cat][<ffffffa7baca35b0>] SyS_read+0x68/0xe0
[ 98.979999] -(1)[4982:cat] ffffffe777c16d00: 00 00 00 00 fc fc fc fc fb fb fb fb fc fc fc fc
[ 98.980012] -(1)[4982:cat] ffffffe777c16e00: fb fb fb fb fc fc fc fc 00 00 00 00 fc fc fc fc
[ 98.980025] -(1)[4982:cat]>ffffffe777c16f00: fb fb fb fb fc fc fc fc fb fb fb fb fc fc fc fc
[ 98.980034] -(1)[4982:cat] ^
如上0xFB标记内存是释放的状态。但对其进行写入,故出现报错。
作者:frank_zyp
您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文无所谓版权,欢迎转载。
最后
以上就是动人中心为你收集整理的内存管理三 内核内存检测KASAN的全部内容,希望文章能够帮你解决内存管理三 内核内存检测KASAN所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复