午夜天堂影院 《魔兽世界》9.0即... 午夜天堂影院 澳大利亚新签证制... 午夜天堂影院 美国也有网恋“杀... 午夜天堂影院 动视第二季度财报... 午夜天堂影院 缺芯进走时:福特...
栏目分类
热点资讯
>> 你的位置:桃花天堂 > 午夜天堂影院 > 午夜天堂影院 在Linux内核行使Kasan

午夜天堂影院 在Linux内核行使Kasan

发布日期:2021-10-12 01:24    点击次数:162

  

1. 序言

KASAN是一个动态检测内存舛讹的工具。KASAN能够检测全局变量、栈、堆分配的内存发生越界访问等题目。功能比SLUB DEBUG齐全并且声援实时检测。越界访问的主要性和危害性议决吾之前的文章(SLUB DEBUG技术)答该有所晓畅。正是由于SLUB DEBUG弱点,因此吾们必要一栽更强化盛的检测工具。难道你不想吗?KASAN就是其中一栽。KASAN的行使真的很浅易。但是吾是一个寻找刨根问底的人。仅仅止步于行使的层面,吾是不情愿的,只有更晓畅的晓畅实现原理才能更加谙练的行使工具。不止是KASAN,其他方面吾也是这么认为。但是,说实话,写这篇文章是有点底气不及的。由于从吾查阅的原料来说,国内异国一篇文章说KASAN的做事原理,国外也是异国什么文章关注KASAN的原理。行家相通都在说How to use。汤姆猫视频最新出口

由于本人程度有限,就根据现有的原料以及本身浏览代码揣摩其中的意思。本文章行为抛准引玉,倘若有分歧理的地方还请指正。

注:文章代码分析基于linux-4.15.0-rc3。

2. 简介

KernelAddressSANitizer(KASAN)是一个动态检测内存舛讹的工具。它为找到use-after-free和out-of-bounds题目挑供了一个迅速和周详的解决方案。KASAN行使编译时检测每个内存访问,因此您必要GCC 4.9.2或更高版本。检测堆栈或全局变量的越界访问必要GCC 5.0或更高版本。现在KASAN仅声援x86_64和arm64架构(linux 4.4版原形符入)。你行使ARM64架构,那么就必要保证linux版本在4.4以上。自然了,倘若你行使的linux也有能够打过KASAN的补丁。例如,行使高通平台做手机的厂商行使linux 3.18同样声援KASAN。

3. 如何行使

行使KASAN工具是比较浅易的,只必要添加kernel以下配置项。

CONFIG_SLUB_DEBUG=y

CONFIG_KASAN=y

为什么这边必须掀开SLUB_DEBUG呢?是由于有段时间KASAN是倚赖SLUBU_DEBUG的,什么意思呢?就是在Kconfig中行使了depends on,晓畅了吧。不过最新的代码已经不必要倚赖了,能够望下挑交。但是吾提出你掀开该选项,由于log能够输出更众有用的新闻。重新编译kernel即可,编译之后你会发现boot.img(Android环境)大幼大了一倍旁边。以是说,影响效果不是异国道理的。不过吾们能够行为产品发布前的末了检查,也能够排查越界访问等题目。吾们能够查望内核日志内容是否包含KASAN检查出的bugs新闻。

4. KASAN是如何实现检测的?

KASAN的原理是行使额外的内存标记可用内存的状态。这片面额外的内存被称作shadow memory(影子区)。KASAN将1/8的内存用作shadow memory。行使稀奇的magic num填充shadow memory,在每一次load/store(load/store检查指令由编译器插入)内存的时候检测对答的shadow memory确定操作是否valid。不息8 bytes内存(8 bytes align)行使1 byte shadow memory标记。倘若8 bytes内存都能够访问,则shadow memory的值为0;倘若不息N(1 =< N <= 7) bytes能够访问,则shadow memory的值为N;倘若8 bytes内存访问都是invalid,则shadow memory的值为负数。

在代码运走时,每一次memory access都会检测对答的shawdow memory的值是否valid。这就必要编译器为吾们做些做事。编译的时候,在每一次memory access前编译器会帮吾们插入__asan_load##size()或者__asan_store##size()函数调用(size是访问内存字节的数目)。这也是请求更新版本gcc的因为,只有更新的版本才声援自动插入。

mov x0, #0x5678  movk x0, #0x1234, lsl #16  movk x0, #0x8000, lsl #32  movk x0, #0xffff, lsl #48  mov w1, #0x5  bl __asan_store1  strb w1, [x0] 

上面一段汇编指令是去0xffff800012345678地址写5。在KASAN掀开的情况下,编译器会帮吾们自动插入bl __asan_store1指令,__asan_store1函数就是检测一个地址对答的shadow memory的值是否批准写1 byte。蓝色汇编指令就是真实的内存访问。因此KASAN能够在out-of-bounds的时候及时检测。__asan_load##size()和__asan_store##size()的代码在mm/kasan/kasan.c文件实现。

4.1. 如何根据shadow memory的值判定内存访问操作是否valid?

shadow memory检测原理的实现主要就是__asan_load##size()和__asan_store##size()函数的实现。那么KASAN是如何根据访问的address以及对答的shadow memory的状态值来判定访问是否相符法呢?最先望一栽最浅易的情况。访问8 bytes内存。

long *addr = (long *)0xffff800012345678; *addr = 0; 

以上代码是访问8 bytes情况,检测原理如下:

long *addr = (long *)0xffff800012345678;  char *shadow = (char *)(((unsigned long)addr >> 3) + KASAN_SHADOW_OFFSE);  if (*shadow)    report_bug();  *addr = 0; 

红色区域相通是编译器插入的指令。既然是访问8 bytes,必须要保证对答的shadow mempry的值必须是0,否则肯定是有题目。那么倘若访问的是1,2 or 4 bytes该如何检查呢?也很浅易,吾们只必要修改一下if判定条件即可。

修改如下:

if (*shadow && *shadow < ((unsigned long)addr & 7) + N); //N = 1,2,4 

倘若*shadow的值为0代外8 bytes均能够访问,自然就不必要report bug。addr & 7是计算访问地址相对于8字节对齐地址的偏移。照样行使下图来表明有关吧。倘若内存是从地址8~15统统8 bytes。对答的shadow memory值为5,现在访问11地址。那么这边的N只要大于2就是invalid。

4.2. shadow memory内存如何分配?

在ARM64中,倘若VA_BITS配置成48。那么kernel space空间大幼是256TB,因此shadow memory的内存必要32TB。吾们必要在虚拟地址空间为KASAN shadow memory分配地址空间。以是吾们有必要晓畅一下ARM64 memory layout。

基于linux-4.15.0-rc3的代码分析,吾绘制了如下memory layout(VA_BITS = 48)。kernel space首首虚拟地址是0xffff_0000_0000_0000,kernel space被分成几个片面别离是KASAN、MODULE、VMALLOC、FIXMAP、PCI_IO、VMEMMAP以及linear mapping。其中KASAN的大幼是32TB,正益是kernel space大幼的1/8。不晓畅你仔细到异国,KERNEL的位置相对以前是不是有所纷歧样。你的印象中,KERNEL是不是位于linear mapping区域,这边怎么变成了VMALLOC区域?这边是Ard Biesheuvel挑交的修改。主要是为了款待ARM64世界的KASLR(which allows the kernel image to be located anywhere in the vmalloc area)的到来。

4.3. 如何竖立shadow memory的映射有关?

当掀开KASAN的时候,KASAN区域位于kernel space首地址处,从0xffff_0000_0000_0000地址最先,大幼是32TB。shadow memory和kernel address转换有关是:shadow_addr = (kaddr >> 3) + KASAN_SHADOW_OFFSE。为了将[0xffff_0000_0000_0000, 0xffff_ffff_ffff_ffff]和[0xffff_0000_0000_0000, 0xffff_1fff_ffff_ffff]对答首来,因此计算KASAN_SHADOW_OFFSE的值为0xdfff_2000_0000_0000。

吾们将KASAN区域放大,如下图所示。

KASAN区域仅仅是分配的虚拟地址,在访问的时候必须竖立和物理地址的映射才能够访问。上图就是KASAN竖立的映射组织。左边是编制启动初期竖立的映射。在kasan_early_init()函数中,将一切的KASAN区域映射到kasan_zero_page物理页面。因此编制启动初期,KASAN并不及做事。右侧是在kasan_init()函数中竖立的映射有关,kasan_init()函数实走终结就预示着KASAN的平常做事。吾们将不必要address sanitizer功能的区域同样照样映射到kasan_zero_page物理页面,并且是readonly。吾们主要是检测kernel和物理内存是否存在UAF或者OOB题目。以是竖立KERNEL和linear mapping(仅仅是一切的物理地址竖立的映射区域)区域对答的shadow memory竖立实在的映射有关。MOUDLE区域对答的shadow memory的映射有关也是必要创建的,但是映射有关竖立是动态的,他在module加载的时候才会去创建映射有关。

4.4. 友人编制分配的内存的shadow memory值如何填充?

既然shadow memory已经竖立映射,接下来的事情就是探究各栽内存分配器向shadow memory填充什么数据了。最先望一下友人编制allocate page(s)函数填充shadow memory情况。

倘若吾们从buddy system分配4 pages。编制最先从order=2的链外中摘下一块内存,然后根据shadow memory address和memory address之间的对答的有关找对答的shadow memory。这边shadow memory的大幼将会是2KB,编制会通盘填充0代外内存能够访问。吾们对分配的内存的肆意地址内存进走访问的时候,最先都会找到对答的shadow memory,然后根据shadow memory value判定访问内存操作是否valid。

倘若开释pages午夜天堂影院,情况又是如何呢?

同样的,当开释pages的时候,会填充shadow memory的值为0xFF。倘若开释之后,照样访问内存的话,此时KASAN根据shadow memory的值是0xFF就能够断,这是一个use-after-free题目。

4.5. SLUB分配对象的内存的shadow memory值如何填充?

当吾们掀开KASAN的时候,SLUB Allocator管理的object layout将会放生必定的转折。如下图所示。

在掀开SLUB_DEBUG的时候,object就添加许众内存,KASAN掀开之后,在此基础上又加了一截。为什么这边必须掀开SLUB_DEBUG呢?是由于有段时间KASAN是倚赖SLUBU_DEBUG的,什么意思呢?就是在Kconfig中行使了depends on,晓畅了吧。不过最新的代码已经不必要倚赖了,能够望下挑交。

当吾们第一次创建slab缓存池的时候,编制会调用kasan_poison_slab()函数初首化shadow memory为下图的模样。整个slab对答的shadow memory都填充0xFC。

上述步骤固然填充了0xFC,但是接下来初首化object的时候,会转折一些shadow memory的值。吾们先望一下kmalloc(20)的情况。吾们晓畅kmalloc()就是基于SLUB Allocator实现的,以是会从kmalloc-32的kmem_cache平分配一个32 bytes object。

最先调用kmalloc(20)函数会匹配到kmalloc-32的kmem_cache,因此实际分配的object大幼是32 bytes。KASAN同样会标记剩下的12 bytes的shadow memory为不走访问状态。根据object的地址,计算shadow memory的地址,并最先填充数值。由于kmalloc()返回的object的size是32 bytes,由于kmalloc(20)只申请了20 bytes,剩下的12 bytes不及行使。KASAN必须标记shadow memory这栽情况。object对答的4 bytes shadow memory别离填充00 00 04 FC。00代外8个不息的字节能够访问。04代外前4个字节能够访问。行为越界访问的检测的手段。统统加在一首是正益是20 bytes可访问。0xFC是Redzone标记。倘若访问了Redzone区域KASAN就会检测out-of-bounds的发生。

当申请行使之后,现在调用kfree()开释之后的shadow memory情况是怎样的呢?望下图。

根据object首地址找到对答的shadow memory,32 bytes object对答4 bytes的shadow memory,现在填充0xFB标记内存是开释的状态。此时倘若不息访问object,那么根据shadow memory的状态值既能够确定是use-after-free题目。

4.6. 全局变量的shadow memory值如何填充?

前线的分析都是基于内存分配器的,Redzone都会随着内存分配器一首分配。那么global variables如何检测呢?global variable的Redzone在那里呢?这就必要编译器入手了。编译器会帮吾们填充Redzone区域。例如吾们定义一个全局变量a,编译器会帮吾们填充成下面的样子。

char a[4];

转换

struct{  char original[4];  char redzone[60];  } a;//32 bytes aligned 

倘若这边你问吾为什么填充60 bytes。其实吾也不晓畅。这个转换例子也是从KASAN作者的PPT中拿过来的。推想要涉及编译器有关的知识,吾无能为力了,但是下面做实验来猜吧。自然了,PPT的内容也必要验证才具有说服力。尽信书则不如无书。吾特地写三个全局变量来验证。发现System.map分配地址之间的差值正益是0x40。因此这边实在是填充60 bytes。

另外从吾的测试发现,倘若上述的数组a的大幼是33的时候,填充的redzone就是63 bytes。以是吾推想,填充的原理是如许的。全局变量实际占用内存总数S(以byte为单位)遵命每块32 bytes平平分成N块。倘若末了一块内存距离现在的32 bytes还差y bytes(if S2 == 0,y = 0),那么redzone填充的大幼就是(y + 32) bytes。画图暗示如下(S2 != 0)。因此总结的规律是:redzone = 63 – (S - 1) % 32。

全局变量redzone区域对答的shadow memory是在什么填充的呢?又是如何调用的呢?这片面是由编译器帮吾们完善的。编译器会为每一个全局变量创建一个函数,函数名称是:

_GLOBAL__sub_I_65535_1_##global_variable_name。

这个函数中议决调用__asan_register_globals()函数完善shadow memory标记。并且将自动生成的这个函数的首地址放在.init_array段。在kernel启动阶段,议决以下代调用有关最后调用一切全局变量的组织函数。kernel_init_freeable()->do_basic_setup() ->do_ctors()。do_ctors()代码实现如下:

staticvoid __init do_ctors(void)  {  ctor_fn_t*fn =(ctor_fn_t*) __ctors_start;  for(; fn <(ctor_fn_t*) __ctors_end; fn++)  (*fn)();  } 

这边的代码意思对于轻车熟路的你再熟识不过了吧。由于内核中这么搞的太众了。便利__ctors_start和__ctors_end之间的一切数据,行为函数地址进走调用,即完善了一切的global variables的shadow memory初首化。吾们能够从链接脚本中晓畅__ctors_start和__ctors_end的意思。

#define KERNEL_CTORS()  . = ALIGN(8);              \             VMLINUX_SYMBOL(__ctors_start) = .; \             KEEP(*(.ctors))            \             KEEP(*(SORT(.init_array.*)))       \             KEEP(*(.init_array))           \             VMLINUX_SYMBOL(__ctors_end) = .; 

上面说了这么众,不晓畅你是否产生了疑心?怎么都是猜啊!猜的能实在吗?是的,吾也这么觉得。是骡子是马,拉出来溜溜呗!现在用原形言语。最先吾创建一个c文件drivers/input/smc.c。在smc.c文件中创建3个全局变量如下:

然后就随意行使吧!编译kernel,吾们先望望System.map文件中,3个全局变量分配的地址。

ffff200009f540e0 B smc_num1  ffff200009f54120 B smc_num2  ffff200009f54160 B smc_num3 

还记得上面说会有一个形如_GLOBAL__sub_I_65535_1_##global_variable_name的函数吗?在System.map文件文件中,吾望到了_GLOBAL__sub_I_65535_1_smc_num1符号。但是异国smc_num2和smc_num3的组织函数。你是不是很清新,不是每一个全局变量都会创建一个相通的组织函数吗?马上为你揭晓。吾们先实走aarch64-linux-gnu-objdump –s –x –d vmlinux > vmlinux.txt命令得到逆编译文件。现在益众主要的新闻在vmlinux.txt。现在主要就是查望vmlinux.txt文件。先望一下_GLOBAL__sub_I_65535_1_smc_num1函数的实现。

ffff200009381df0 <_GLOBAL__sub_I_65535_1_smc_num1>:  ffff200009381df0: a9bf7bfd stp x29, x30, [sp,#-16]!  ffff200009381df4: b0001800 adrp x0, ffff200009682000  ffff200009381df8: 91308000 add x0, x0, #0xc20  ffff200009381dfc: d2800061 mov x1, #0x3 // #3  ffff200009381e00: 910003fd mov x29, sp  ffff200009381e04: 9100c000 add x0, x0, #0x30  ffff200009381e08: 97c09fb8 bl ffff2000083a9ce8 <__asan_register_globals>  ffff200009381e0c: a8c17bfd ldp x29, x30, [sp],#16  ffff200009381e10: d65f03c0 ret 

汇编和C语言传递参数在ARM64平台行使的是x0~x7。议决上面的汇编计算一下,x0=0xffff200009682c50,x1=3。然后调用__asan_register_globals()函数,x0和x1就是传递的参数。吾们望一下__asan_register_globals()函数实现。

void __asan_register_globals(struct kasan_global *globals,size_t size)  {  int i;  for(i =0; i < size; i++)          register_global(&globals[i]);  } 

size是3就是要初首化全局变量的个数,以是这边只必要一个组织函数即可。一次性将3个全局变量通盘搞定。这边再说一点推想吧!吾推想是以文件为单位编译器创建一个组织函数即可,将本文件全局变量一次性通盘打包初首化。第一个参数globals是0xffff200009682c50,不息从vmlinux.txt中查望该地址处的数据。struct kasan_global是编译器帮吾们自动创建的组织体,每一个全局变量对答一个struct kasan_global组织体。struct kasan_global组织体存放的位置是.data段,因此吾们能够从.data段查找现在地址对答的数据。

数据如下:

ffff200009682c50 6041f509 0020ffff 07000000 00000000  ffff200009682c60 40000000 00000000 d0d62b09 0020ffff  ffff200009682c70 b8d62b09 0020ffff 00000000 00000000  ffff200009682c80 202c6809 0020ffff 2041f509 0020ffff  ffff200009682c90 1f000000 00000000 40000000 00000000  ffff200009682ca0 e0d62b09 0020ffff b8d62b09 0020ffff  ffff200009682cb0 00000000 00000000 302c6809 0020ffff  ffff200009682cc0 e040f509 0020ffff 04000000 00000000  ffff200009682cd0 40000000 00000000 f0d62b09 0020ffff  ffff200009682ce0 b8d62b09 0020ffff 00000000 00000000 

最先ffff200009682c50对答的第一个数据6041f509 0020ffff,这是个啥?其实是一个地址数据,你是不是又疑问了,ARM64的kernel space地址不是ffff起头吗?这个怎么60起头?其实这个地址数据是逆过来的,你答该从右向左望。这个地址其实是ffff200009f54160。这不正是smc_num3的地址嘛!解析这段数据之前必要晓畅一下struct kasan_global组织体。

/* The layout of struct dictated by compiler */  struct kasan_global {  constvoid*beg;/* Address of the beginning of the global variable. */  size_t size;/* Size of the global variable. */  size_t size_with_redzone;/* Size of the variable + size of the red zone. 32 bytes aligned */  constvoid*name;  constvoid*module_name;/* Name of the module where the global variable is declared. */  unsignedlong has_dynamic_init;/* This needed for C++ */  #if KASAN_ABI_VERSION >= 4  struct kasan_source_location *location;  #endif  }; 

第一个成员beg就是全局变量的首地址。跟上面的分析相反。第二个成员size从上面数据望出是7,正益对答吾们定义的smc_num3[7],正益7 bytes。size_with_redzone的值是0x40,正益是64。根据上面推想redzone=63-(7-1)2=57。加上size正益是64,表明之前推想的redzone计算手段没错。name成员对答的地址是ffff2000092bd6d0。

望下ffff2000092bd6d0存储的是什么。

ffff2000092bd6d0 736d635f 6e756d33 00000000 00000000 smc_num3........ 

以是name就是全局变量的名称转换成字符串。同样的手段得到module_name的地址是ffff2000092bd6b8。不息望望这段地址存储的数据。

ffff2000092bd6b0 65000000 00000000 64726976 6572732f e.......drivers/  ffff2000092bd6c0 696e7075 742f736d 632e6300 00000000 input/smc.c..... 

一现在了然,module_name是文件的路径。has_dynamic_init的值就是0,这是C++必要的。吾用的GCC版本是5.0旁边,以是这边的KASAN_ABI_VERSION=4。这边location成员的地址是ffff200009682c20,不息追踪该地址的数据。

ffff200009682c20 b8d62b09 0020ffff 0e000000 0f000000 

解析这段数据之前要先晓畅struct kasan_source_location组织体。

/* The layout of struct dictated by compiler */  struct kasan_source_location {  constchar*filename;  int line_no;  int column_no;  }; 

第一个成员filename地址是ffff2000092bd6b8和module_name相通的数据。剩下两个数据别离是14和15,别离代外全局变量定义地方的走号和列号。现在回到上面吾定义变量的截图,仔细数数列号是不是15,走号截图中也有哦!特地截出来给你望的。剩下的struct kasan_global数据就是smc_num1和smc_num2的数据。分析就不说了。前线说_GLOBAL__sub_I_65535_1_smc_num1函数会被自动调用,该地址数据填充在__ctors_start和__ctors_end之间。现在也表明一下不悦目点。

先从System.map得到符号的地址数据。

ffff2000093ac5d8 T __ctors_start  ffff2000093ae860 T __ctors_end 

然后搜索一下_GLOBAL__sub_I_65535_1_smc_num1的地址ffff200009381df0被存储在什么位置,记得搜索的关键字是f01d3809 0020ffff。

ffff2000093ae0c0 f01d3809 0020ffff 181e3809 0020ffff 

能够望出ffff2000093ae0c0地址处存储着_GLOBAL__sub_I_65535_1_smc_num1函数地址。这个地址不是正益位于__ctors_start和__ctors_end之间嘛!

现在就剩下__asan_register_globals()函数到底是是怎么初首化shadow memory的呢?以char a[4]为例,如下图所示。

a[4]只有4 bytes能够访问,以是对答的shadow memory的第一个byte值是4,后面的redzone就填充0xFA行为越界检测。a[4]只有4 bytes能够访问,以是对答的shadow memory的第一个byte值是4,后面的redzone就填充0xFA行为越界检测。由于这边是全局变量,因此分配的内存区域位于kernel区域。

4.7. 栈分配变量的readzone是如何分配的?

从栈平分配的变量同样和全局变量相通必要填充一些内存行为redzone区域。下面不息举个例子表明编译器怎么填充。最先来一段平常的代码,异国编译器的插手。

void foo()  {  char a[328];  } 

再来望望编译器插了哪些东西进去。

void foo() {     char rz1[32];     char a[328];     char rz2[56];     int *shadow = (&rz1 >> 3)+ KASAN_SHADOW_OFFSE;     shadow[0] = 0xffffffff;     shadow[11] = 0xffffff00;     shadow[12] = 0xffffffff; ------------------------行使完毕----------------------------------------     shadow[0] = shadow[11] = shadow[12] = 0; } 

红色片面是编译器填充内存,rz2是56,能够根据上一节全局变量的公式套用计算得到。但是这边在变量前线竟然还有32 bytes的rz1。这个是和全局变量的分歧,吾推想这边是为了检测栈变量左边界越界题目。蓝色片面代码也是编译器填充,初首化shadow memory。栈的填充就异国探究那么深入了,风趣味的读者能够本身探究。

5. Error log新闻包含哪些新闻?

从kernel的Documentation文档找份典型的KASAN bug输出的log新闻如下。

==================================================================  BUG: AddressSanitizer: out of bounds access in kmalloc_oob_right+0x65/0x75 [test_kasan] at addr ffff8800693bc5d3  Write of size 1 by task modprobe/1689  =============================================================================  BUG kmalloc-128 (Not tainted): kasan error  -----------------------------------------------------------------------------  Disabling lock debugging due to kernel taint  INFO: Allocated in kmalloc_oob_right+0x3d/0x75 [test_kasan] age=0 cpu=0 pid=1689  __slab_alloc+0x4b4/0x4f0  kmem_cache_alloc_trace+0x10b/0x190  kmalloc_oob_right+0x3d/0x75 [test_kasan]  init_module+0x9/0x47 [test_kasan]  do_one_initcall+0x99/0x200  load_module+0x2cb3/0x3b20  SyS_finit_module+0x76/0x80  system_call_fastpath+0x12/0x17  INFO: Slab 0xffffea0001a4ef00 objects=17 used=7 fp=0xffff8800693bd728 flags=0x100000000004080  INFO: Object 0xffff8800693bc558 @offset=1368 fp=0xffff8800693bc720  Bytes b4 ffff8800693bc548: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ  Object ffff8800693bc558: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk  Object ffff8800693bc568: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk  Object ffff8800693bc578: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk  Object ffff8800693bc588: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk  Object ffff8800693bc598: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk  Object ffff8800693bc5a8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk  Object ffff8800693bc5b8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk  Object ffff8800693bc5c8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk.  Redzone ffff8800693bc5d8: cc cc cc cc cc cc cc cc ........  Padding ffff8800693bc718: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ  CPU: 0 PID: 1689 Comm: modprobe Tainted: G B 3.18.0-rc1-mm1+ #98  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014  ffff8800693bc000 0000000000000000 ffff8800693bc558 ffff88006923bb78  ffffffff81cc68ae 00000000000000f3 ffff88006d407600 ffff88006923bba8  ffffffff811fd848 ffff88006d407600 ffffea0001a4ef00 ffff8800693bc558  Call Trace:  [] dump_stack+0x46/0x58  [] print_trailer+0xf8/0x160  [] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]  [] object_err+0x35/0x40  [] ? kmalloc_oob_right+0x65/0x75 [test_kasan]  [] kasan_report_error+0x38a/0x3f0  [] ? kasan_poison_shadow+0x2f/0x40  [] ? kasan_unpoison_shadow+0x14/0x40  [] ? kasan_poison_shadow+0x2f/0x40  [] ? kmem_cache_oob+0xc3/0xc3 [test_kasan]  [] __asan_store1+0x75/0xb0  [] ? kmem_cache_oob+0x1d/0xc3 [test_kasan]  [] ? kmalloc_oob_right+0x65/0x75 [test_kasan]  [] kmalloc_oob_right+0x65/0x75 [test_kasan]  [] init_module+0x9/0x47 [test_kasan]  [] do_one_initcall+0x99/0x200  [] ? __vunmap+0xec/0x160  [] load_module+0x2cb3/0x3b20  [] ? m_show+0x240/0x240  [] SyS_finit_module+0x76/0x80  [] system_call_fastpath+0x12/0x17  Memory state around the buggy address:  ffff8800693bc300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc  ffff8800693bc380: fc fc 00 00 00 00 00 00 00 00 00 00 00 00 00 fc  ffff8800693bc400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc  ffff8800693bc480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc  ffff8800693bc500: fc fc fc fc fc fc fc fc fc fc fc 00 00 00 00 00  >ffff8800693bc580: 00 00 00 00 00 00 00 00 00 00 03 fc fc fc fc fc  ^  ffff8800693bc600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc  ffff8800693bc680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc  ffff8800693bc700: fc fc fc fc fb fb fb fb fb fb fb fb fb fb fb fb  ffff8800693bc780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb  ffff8800693bc800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb  ================================================================== 

输出的新闻很雄厚,包含了bug发生的类型、SLUB输出的object内存新闻、Call Trace以及shadow memory的状态值。其中红色新闻都是比较主要的新闻。吾异国写demo历程,而是找了一份log新闻,不是吾想偷懒,而是锻炼本身。怎么锻炼呢?吾想问的是,从这份log中你能够推想代码答该是怎么样的?

吾能够得到一下新闻:

1) 程序是议决kmalloc接口申请内存的;

2) 申请的内存大幼是123 bytes,即p = kamlloc(123);

3) 代码中相通去p[123]中写1 bytes导致越界访问的bug;

4) 在3)步骤发生前异国任何的对该内存的写操作;

倘若你也能得到以上4点推想,吾觉的吾写的这几篇文章你是真的望晓畅了。最先输出新闻是有SLUB的新闻,以是答该是议决kmalloc()接口;在打印的shadow memory的值中,吾们望到不息的15个0和一个3,以是申请的内存size就是15x8+3=123;由于是去ffff8800693bc5d3地址写1个字节,并且object首地址是ffff8800693bc558,以是推想是去p[123]写1 byte出题目;由于log中将object中一切的128 bytes数据通盘打印出来,统统是127个0x6b和一个0xa5(SLUB DEBUG文章介绍的内容)。以是吾推想在3)步骤发生前异国任何的对该内存的写操作。

6. 补充

吾望了linux-4.18的代码,KASAN的log输出已经发生了片面转折。例如:上面举例的SLUB的object的内容就不会打印了。吾们用一下的程序展现这些转折(实际上就是上面举例用的程序)。

static noinline void __init kmalloc_oob_right(void)  {  char*ptr;  size_t size =123;        ptr = kmalloc(size, GFP_KERNEL);  if(!ptr){          pr_err("Allocation failed\n");  return;      }      ptr[size]='x';      kfree(ptr);  } 

针对以上代码,KASAN检测到bug后的输出log如下:

==================================================================  BUG: KASAN: slab-out-of-bounds in kmalloc_oob_right+0x6c/0x8c  Write of size 1 at addr ffffffc0cb114d7b by task swapper/0/1     CPU: 4 PID: 1 Comm: swapper/0 Tainted: G S      W       4.9.82-perf+ #310  Hardware name:QualcommTechnologies,Inc. SDM632 PMI632  Call trace:  [<ffffff90cf88d9f8>] dump_backtrace+0x0/0x320  [<ffffff90cf88dd2c>] show_stack+0x14/0x20  [<ffffff90cfdd1148>] dump_stack+0xa8/0xd0  [<ffffff90cfabf298>] print_address_description+0x60/0x250  [<ffffff90cfabf6a0>] kasan_report.part.2+0x218/0x2f0  [<ffffff90cfabfac0>] kasan_report+0x20/0x28  [<ffffff90cfabdc64>] __asan_store1+0x4c/0x58  [<ffffff90d1a4f760>] kmalloc_oob_right+0x6c/0x8c  [<ffffff90d1a50448>] kmalloc_tests_init+0xc/0x68  [<ffffff90cf8845dc>] do_one_initcall+0xa4/0x1f0  [<ffffff90d1a011ac>] kernel_init_freeable+0x244/0x300  [<ffffff90d0d6da70>] kernel_init+0x10/0x110  [<ffffff90cf8842a0>] ret_from_fork+0x10/0x30     Allocatedby task 1:   kasan_kmalloc+0xd8/0x188   kmem_cache_alloc_trace+0x130/0x248  kmalloc_oob_right+0x4c/0x8c   kmalloc_tests_init+0xc/0x68   do_one_initcall+0xa4/0x1f0   kernel_init_freeable+0x244/0x300   kernel_init+0x10/0x110  ret_from_fork+0x10/0x30     Freedby task 1:   kasan_slab_free+0x88/0x178   kfree+0x84/0x298  kobject_uevent_env+0x144/0x620   kobject_uevent+0x10/0x18   device_add+0x5f8/0x860   amba_device_try_add+0x22c/0x2f8   amba_device_add+0x20/0x128  of_platform_bus_create+0x390/0x478   of_platform_bus_create+0x21c/0x478   of_platform_populate+0x4c/0xb8   of_platform_default_populate_init+0x78/0x8c   do_one_initcall+0xa4/0x1f0  kernel_init_freeable+0x244/0x300   kernel_init+0x10/0x110   ret_from_fork+0x10/0x30     The buggy address belongs to the object at ffffffc0cb114d00  which belongs to the cache kmalloc-128 of size 128  The buggy address is located 123 bytes inside of  128-byte region [ffffffc0cb114d00, ffffffc0cb114d80)  The buggy address belongs to the page:  page:ffffffbf032c4500 count:1 mapcount:0 mapping:(null) index:0xffffffc0cb115200 compound_mapcount:0  flags: 0x4080(slab|head)  page dumped because: kasan: bad access detected     Memory state around the buggy address:   ffffffc0cb114c00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc  ffffffc0cb114c80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc  >ffffffc0cb114d00:00000000000000000000000000000003  ^   ffffffc0cb114d80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc   ffffffc0cb114e00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc  ================================================================== 

吾们从上面的log能够分析如下数据:

line2:发生越界访问位置。 line3:越界写1个字节,写的地址是0xffffffc0cb114d7b。现在进程是comm是swapper/0,pid是1。 line7:Call trace,方便定位出题目的函数调用有关。 line22:该object分配的调用栈,并指出分配内存的进程pid是1。 line32:开释该object的调用栈(上次开释),并指出开释内存的进程pid是1。 line49:指出slub有关的新闻,从“kmalloc-28”的kmem_cache分配的object。object首首地址是0xffffffc0cb114d00。 line51:访问出题目的地址位于object首首地址偏移123 bytes的位置。object的地址周围是[0xffffffc0cb114d00, 0xffffffc0cb114d80)。object实际大幼是128 bytes。 line61:出题目地址对答的shadow memory的值,能够确定申请内存的实际大幼是123 bytes。 参考文献:

1.How to use KASAN to debug memory corruption in OpenStack environment.pdf

2.KernelAddressSanitizer (KASan) a fast memory error detector for the Linux kernel.pdf

【编辑选举】午夜天堂影院

鸿蒙官方战略配相符共建——HarmonyOS技术社区Linux Mint 20.3 宣布将在圣诞节前发布:改进主题,官网焕然一新无广告Linux Mint 和 Fedora:答该行使哪一个?Linux 5.16 将实现更益的 USB 矮耽延音频播放如何切确配置Linux存储库嵌入式Linux网络编程视频课程

上一篇:午夜天堂影院 2021届高三第二次大联考语文试题(有答案)

下一篇:午夜天堂影院 《道德经》:舛讹的认知,是人生糟糕的最先

Powered by 桃花天堂 @2013-2021 RSS地图 HTML地图