Linux常见的内存访问错误有:越界访问(outofbounds)访问已经释放的内存(useafterfree)重复释放内存泄露(memoryleak)栈溢出(stackoverflow)不同的工具有不同的侧重点,本章主要从slubdebug、kmemleak、kasan三个工具介绍。kmemleak侧重于内存泄露问题发现。slubdebug和kasan有一定的重复,部分slubdebug问题需要借助slabinfo去发现;kasan更快,所有问题独立上报,缺点是需要高版本GCC支持(gcc4。9。2orgcc5。0)。测试环境准备更新内核版本到Kernelv4。4,然后编译:gitclonehttps:github。comarnoldlulinux。gitbrunningkernel4。4 exportARCHarm64 exportCROSSCOMPILEaarch64linuxgnu makedefconfig makebzImagej4ARCHarm64CROSSCOMPILEaarch64linuxgnuslubdebug关键词:RedZone、Padding、ObjectLayout。Linux内核中,小块内存大量使用slabslub分配器,slubdebug提供了内存检测小功能。内存中比较容易出错的地方有:访问已经释放的内存越界访问重复释放内存编译支持slubdebug内核首先需要打开GeneralsetupEnableSLUBdebuggingsupport,然后再选择KernelhackingMemoryDebuggingSLUBdebuggingonbydefault。CONFIGSLUBy CONFIGSLUBDEBUGy CONFIGSLUBDEBUGONy CONFIGSLUBSTATSy测试环境:slabinfo、slub。ko通过slub。ko模拟内存异常访问,有些可以直接显示,有些需要通过slabinfov来查看。在toolsvm目录下,执行如下命令,生成可执行文件slabinfo。放入install目录,打包到zImage中。 makeslabinfoCFLAGSstaticARCHarmCROSSCOMPILEarmlinuxgnueabi将编译好的slabinfo放入sbin。下面三个测试代码:https:github。comarnoldlulinuxtreerunningkernel4。4testcodeslubdebug在testcodeslubdebug目录下执行make。sh,将slub。koslub2。koslub3。ko放入data。进行测试启动QEMU: qemusystemaarch64machinevirtcpucortexa57machinetypevirtsmp2m2048kernelarcharm64bootImageappendrdinitlinuxrcconsolettyAMA0loglevel8slubdebugUFPZnographic F:在free的时候会执行检查。 Z:表示RedZone的意思。 P:是Poison的意思。 U:会记录slab的使用者信息,如果打开,会会显示分配释放对象的栈回溯。在slubdebug打开SLABSTOREUSER选项后,可以清晰地看到问题点的backtrace。测试结果内存越界访问包括Redzoneoverwritten和Objectpaddingoverwritten。重复释放对应Objectalreadyfree。访问已释放内存为Posionoverwritten。 Redzoneoverwritten执行insmoddataslub。ko,使用slabinfov查看结果。staticvoidcreatesluberror(void){bufkmalloc(32,GFPKERNEL);if(buf){memset(buf,0x55,80);虽然分配32字节,但是对应分配了64字节。所以设置为80字节访问触发异常。从buf开始的80个字节仍然被初始化成功。}}虽然kmalloc申请了32字节的slab缓冲区,但是内核分配的是kmalloc64。所以memset36字节不会报错,将36改成大于64即可。一个slubDebug输出包括四大部分:BUGkmalloc64(Tainted:GO):Redzoneoverwritten1。问题描述:slab名称kmalloc64,什么错误Redzoneoverwritten。DisablinglockdebuggingduetokerneltaintINFO:0xeddb36400xeddb3643。Firstbyte0x55insteadof0xcc1。1问题起始和结束地址,这里一共4字节。INFO:Allocatedin0x55555555age1766cpu0pid7711。2slab的分配栈回溯0x555555550xbf002014dooneinitcall0x900x1d8doinitmodule0x600x38cloadmodule0x1bac0x1e94SySinitmodule0x14c0x15cretfastsyscall0x00x3cINFO:Freedindooneinitcall0x780x1d8age1766cpu0pid7711。3slab的释放栈回溯dooneinitcall0x780x1d8doinitmodule0x600x38cloadmodule0x1bac0x1e94SySinitmodule0x14c0x15cretfastsyscall0x00x3cINFO:Slab0xefdb5660objects16used14fp0xeddb3700flags0x00811。4slab的地址,以及其它信息。INFO:Object0xeddb3600offset1536fp0x555555551。5当前Object起始,及相关信息Bytesb4eddb35f0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZ2。问题slab对象内容。2。1打印问题slab对象内容之前一些字节。Objecteddb3600:55555555555555555555555555555555UUUUUUUUUUUUUUUU2。2slab对象内容,全部为0x55。Objecteddb3610:55555555555555555555555555555555UUUUUUUUUUUUUUUUObjecteddb3620:55555555555555555555555555555555UUUUUUUUUUUUUUUUObjecteddb3630:55555555555555555555555555555555UUUUUUUUUUUUUUUURedzoneeddb3640:55555555UUUU2。3Redzone内容,问题出在这里。Paddingeddb36e8:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZ2。4Padding内容,为了对象对齐而补充。Paddingeddb36f8:5a5a5a5a5a5a5a5aZZZZZZZZCPU:2PID:773Comm:slabinfoTainted:GBO4。4。0933。检查问题点的栈打印,这里是由于slabinfo找出来的。Hardwarename:ARMVersatileExpress〔c0016588〕(unwindbacktrace)from〔c0013070〕(showstack0x100x14)〔c0013070〕(showstack)from〔c0244130〕(dumpstack0x780x88)〔c0244130〕(dumpstack)from〔c00e1874〕(checkbytesandreport0xd00x10c)〔c00e1874〕(checkbytesandreport)from〔c00e1a14〕(checkobject0x1640x234)〔c00e1a14〕(checkobject)from〔c00e29bc〕(validateslabslab0x1980x1bc)〔c00e29bc〕(validateslabslab)from〔c00e578c〕(validatestore0xac0x190)〔c00e578c〕(validatestore)from〔c0146780〕(kernfsfopwrite0xb80x1b4)〔c0146780〕(kernfsfopwrite)from〔c00ebfc4〕(vfswrite0x1c0xd8)〔c00ebfc4〕(vfswrite)from〔c00ec808〕(vfswrite0x900x170)〔c00ec808〕(vfswrite)from〔c00ed008〕(SySwrite0x3c0x90)〔c00ed008〕(SySwrite)from〔c000f3c0〕(retfastsyscall0x00x3c)FIXkmalloc64:Restoring0xeddb36400xeddb36430xcc4。问题点是如何被解决的,此处恢复4个字节为0xcc。 Objectpaddingoverwrittenvoidcreatesluberror(void){bufkmalloc(32,GFPKERNEL);if(buf){buf〔1〕0x55;向左越界访问kfree(buf);}}执行insmoddataslub4。ko,结果如下。这里的越界访问和之前有点不一样的是,这里向左越界。覆盖到了Padding区域。al:sluberrortestinitBUGkmalloc128(Tainted:GO):Objectpaddingoverwritten覆盖到Padding区域DisablinglockdebuggingduetokerneltaintINFO:0xffff80007767e9ff0xffff80007767e9ff。Firstbyte0x55insteadof0x5aINFO:Allocatedincallusermodehelpersetup0x440xb8age1cpu1pid789allocdebugprocessing0x17c0x188slaballoc。constprop。300x3f80x440slaballoc。isra。27。constprop。290x240x38kmemcachealloc0x1ec0x260callusermodehelpersetup0x440xb8kobjectueventenv0x4940x500kobjectuevent0x100x18loadmodule0x18cc0x1d78SySinitmodule0x1500x178el0svcnaked0x240x28INFO:Slab0xffff7bffc2dd9f80objects16used9fp0xffff80007767ea00flags0x4081INFO:Object0xffff80007767e800offset2048fp0xffff80007767ea00Bytesb4ffff80007767e7f0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZObjectffff80007767e800:000100000000000008e867770080ffff。。。。。。。。。。gw。。。。Objectffff80007767e810:08e867770080fffff8830c000080ffff。。gw。。。。。。。。。。。。Objectffff80007767e820:0000000000000000006eaa000080ffff。。。。。。。。。n。。。。。。Objectffff80007767e830:002367780080ffff182367780080ffff。gx。。。。。gx。。。。Objectffff80007767e840:00000000000000000000000000000000。。。。。。。。。。。。。。。。Objectffff80007767e850:b88e32000080ffff002367780080ffff。。2。。。。。。gx。。。。Objectffff80007767e860:00000000000000000000000000000000。。。。。。。。。。。。。。。。Objectffff80007767e870:00000000000000000000000000000000。。。。。。。。。。。。。。。。Redzoneffff80007767e880:cccccccccccccccc。。。。。。。。Paddingffff80007767e9c0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZPaddingffff80007767e9d0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZPaddingffff80007767e9e0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZPaddingffff80007767e9f0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a55ZZZZZZZZZZZZZZZUCPU:0PID:790Comm:mdevTainted:GBO4。4。0116Hardwarename:linux,dummyvirt(DT)Calltrace:〔ffff800000089738〕dumpbacktrace0x00x108〔ffff800000089854〕showstack0x140x20〔ffff8000003253c4〕dumpstack0x940xd0〔ffff800000196460〕printtrailer0x1280x1b8〔ffff800000196848〕checkbytesandreport0xd80x118〔ffff800000196928〕checkobject0xa00x240〔ffff8000001987e0〕freedebugprocessing0x1280x380〔ffff80000019a1cc〕slabfree0x3440x4a0〔ffff80000019ab94〕kfree0x1ec0x220〔ffff8000000c8278〕umhcomplete0x580x68〔ffff8000000c83d8〕callusermodehelperexecasync0x1500x170〔ffff800000085c50〕retfromfork0x100x40FIXkmalloc128:Restoring0xffff80007767e9ff0xffff80007767e9ff0x5a问题处理是将对应字节恢复为0x5a。 Objectalreadyfreevoidcreatesluberror(void){bufkmalloc(32,GFPKERNEL);if(buf){memset(buf,0x55,32);kfree(buf);printk(al:Objectalreadyfreed);kfree(buf);}}内核中free执行流程如下:kfreeslabfreeslabfreekmemcachedebugfreedebugprocessingonfreelist执行insmoddataslub2。ko,结果如下。al:sluberrortestinital:ObjectalreadyfreedBUGkmalloc128(Tainted:GBO):Objectalreadyfree在64位系统,32字节的kmalloc变成了kmalloc128,问题类型是:Objectalreadyfree,也即重复释放。INFO:Allocatedincreatesluberror0x200x80〔slub2〕age0cpu1pid791内存分配点栈回溯allocdebugprocessing0x17c0x188slaballoc。constprop。300x3f80x440slaballoc。isra。27。constprop。290x240x38kmemcachealloc0x1ec0x260createsluberror0x200x80〔slub2〕mytestinit0x140x28〔slub2〕dooneinitcall0x900x1a0doinitmodule0x600x1ccloadmodule0x18dc0x1d78SySinitmodule0x1500x178el0svcnaked0x240x28INFO:Freedincreatesluberror0x500x80〔slub2〕age0cpu1pid791内存释放点栈回溯freedebugprocessing0x17c0x380slabfree0x3440x4a0kfree0x1ec0x220createsluberror0x500x80〔slub2〕mytestinit0x140x28〔slub2〕dooneinitcall0x900x1a0doinitmodule0x600x1ccloadmodule0x18dc0x1d78SySinitmodule0x1500x178el0svcnaked0x240x28INFO:Slab0xffff7bffc2dda800objects16used7fp0xffff8000776a0800flags0x4081INFO:Object0xffff8000776a0800offset2048fp0xffff8000776a0a00Bytesb4ffff8000776a07f0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZObjectffff8000776a0800:6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkk内存内容打印,供128字节。Objectffff8000776a0810:6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkkObjectffff8000776a0820:6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkkObjectffff8000776a0830:6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkkObjectffff8000776a0840:6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkkObjectffff8000776a0850:6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkkObjectffff8000776a0860:6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkkObjectffff8000776a0870:6b6b6b6b6b6b6b6b6b6b6b6b6b6b6ba5kkkkkkkkkkkkkkk。Redzoneffff8000776a0880:bbbbbbbbbbbbbbbb。。。。。。。。Paddingffff8000776a09c0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZPaddingffff8000776a09d0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZPaddingffff8000776a09e0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZPaddingffff8000776a09f0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZCPU:1PID:791Comm:insmodTainted:GBO4。4。0116此处问题在insmod就发现了,所以检查出问题的进程就是insmod。Hardwarename:linux,dummyvirt(DT)Calltrace:〔ffff800000089738〕dumpbacktrace0x00x108〔ffff800000089854〕showstack0x140x20〔ffff8000003253c4〕dumpstack0x940xd0〔ffff800000196460〕printtrailer0x1280x1b8〔ffff800000198954〕freedebugprocessing0x29c0x380〔ffff80000019a1cc〕slabfree0x3440x4a0〔ffff80000019ab94〕kfree0x1ec0x220〔ffff7ffffc008060〕createsluberror0x600x80〔slub2〕〔ffff7ffffc00a014〕mytestinit0x140x28〔slub2〕〔ffff800000082930〕dooneinitcall0x900x1a0〔ffff80000014647c〕doinitmodule0x600x1cc〔ffff800000120704〕loadmodule0x18dc0x1d78〔ffff800000120cf0〕SySinitmodule0x1500x178〔ffff800000085cb0〕el0svcnaked0x240x28FIXkmalloc128:Objectat0xffff8000776a0800notfreed处理的结果是,此处slab对象是没有被释放。 Poisonoverwritten访问已释放内存的测试代码如下:staticvoidcreatesluberror(void){bufkmalloc(32,GFPKERNEL);此时的buf内容都是0x6Bif(buf){kfree(buf);printk(al:Accessafterfree);memset(buf,0x55,32);虽然被释放,但是memset仍然生效了变成了0x55。}}执行insmoddataslub3。ko,使用slabinfov查看结果。BUGkmalloc128(Tainted:GBO):Poisonoverwrittenslab名称为kmalloc64,问题类型是:Poisonoverwritten,即访问已释放内存。INFO:0xffff8000776928000xffff80007769281f。Firstbyte0x55insteadof0x6bINFO:Allocatedincreatesluberror0x280xf0〔slub3〕age1089cpu1pid793分配点的栈回溯allocdebugprocessing0x17c0x188slaballoc。constprop。300x3f80x440slaballoc。isra。27。constprop。290x240x38kmemcachealloc0x1ec0x260createsluberror0x280xf0〔slub3〕0xffff7ffffc00e014dooneinitcall0x900x1a0doinitmodule0x600x1ccloadmodule0x18dc0x1d78SySinitmodule0x1500x178el0svcnaked0x240x28INFO:Freedincreatesluberror0x800xf0〔slub3〕age1089cpu1pid793释放点的栈回溯freedebugprocessing0x17c0x380slabfree0x3440x4a0kfree0x1ec0x220createsluberror0x800xf0〔slub3〕0xffff7ffffc00e014dooneinitcall0x900x1a0doinitmodule0x600x1ccloadmodule0x18dc0x1d78SySinitmodule0x1500x178el0svcnaked0x240x28INFO:Slab0xffff7bffc2dda480objects16used16fp0x(null)flags0x4080INFO:Object0xffff800077692800offset2048fp0xffff800077692400Bytesb4ffff8000776927f0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZObjectffff800077692800:55555555555555555555555555555555UUUUUUUUUUUUUUUU前32字节仍然被修改成功。Objectffff800077692810:55555555555555555555555555555555UUUUUUUUUUUUUUUUObjectffff800077692820:6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkkObjectffff800077692830:6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkkObjectffff800077692840:6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkkObjectffff800077692850:6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkkObjectffff800077692860:6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkkObjectffff800077692870:6b6b6b6b6b6b6b6b6b6b6b6b6b6b6ba5kkkkkkkkkkkkkkk。Redzoneffff800077692880:bbbbbbbbbbbbbbbb。。。。。。。。Paddingffff8000776929c0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZPaddingffff8000776929d0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZPaddingffff8000776929e0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZPaddingffff8000776929f0:5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5aZZZZZZZZZZZZZZZZCPU:0PID:795Comm:slabinfoTainted:GBO4。4。0116Hardwarename:linux,dummyvirt(DT)Calltrace:〔ffff800000089738〕dumpbacktrace0x00x108〔ffff800000089854〕showstack0x140x20〔ffff8000003253c4〕dumpstack0x940xd0〔ffff800000196460〕printtrailer0x1280x1b8〔ffff800000196848〕checkbytesandreport0xd80x118〔ffff800000196a54〕checkobject0x1cc0x240〔ffff800000197920〕allocdebugprocessing0x1080x188〔ffff800000199670〕slaballoc。constprop。300x3f80x440〔ffff8000001996dc〕slaballoc。isra。27。constprop。290x240x38〔ffff8000001998dc〕kmemcachealloc0x1ec0x260〔ffff8000001d42fc〕seqopen0x340x90〔ffff80000022059c〕kernfsfopopen0x1940x370〔ffff8000001afb04〕dodentryopen0x2140x318〔ffff8000001b0dc8〕vfsopen0x580x68〔ffff8000001bf338〕pathopenat0x4600xdf0〔ffff8000001c0ff0〕dofilpopen0x600xe0〔ffff8000001b117c〕dosysopen0x12c0x218〔ffff8000001fd53c〕compatSySopen0x1c0x28〔ffff800000085cb0〕el0svcnaked0x240x28FIXkmalloc128:Restoring0xffff8000776928000xffff80007769281f0x6bFIXkmalloc128:MarkingallobjectsusedSLUB:kmalloc128210slabscountedbutcounter211slabinfo(795)usedgreateststackdepth:12976bytesleftkmemleakkmemleak是内核提供的一种检测内存泄露工具,启动一个内核线程扫描内存,并打印发现新的未引用对象数量。支持kmemleak内核选项要使用kmemlieak,需要打开如下内核选项。KernelhackingMemoryDebuggingKernelmemoryleakdetector: CONFIGHAVEDEBUGKMEMLEAKyCONFIGDEBUGKMEMLEAKyCONFIGDEBUGKMEMLEAKEARLYLOGSIZE400CONFIGDEBUGKMEMLEAKTESTisnotsetCONFIGDEBUGKMEMLEAKDEFAULTOFFy或者关闭此选项,则不需要在命令行添加kmemleakon。构造测试环境同时还需要在内核启动命令行中添加kmemleakon。 qemusystemaarch64machinevirtcpucortexa57machinetypevirtsmp2m2048kernelarcharm64bootImageappendrdinitlinuxrcconsolettyAMA0loglevel8voidcreatekmemleak(void){bufkmalloc(120,GFPKERNEL);bufvmalloc(4096);}进行测试进行kmemleak测试之前,需要写入scan触发扫描操作。然后通过读kmemlean节点读取相关信息。打开kmemlean扫描功能:echoscansyskerneldebugkmemleak加载问题module:insmoddatakmemleak。ko等待问题发现:kmemleak:2newsuspectedmemoryleaks(seesyskerneldebugkmemleak)查看kmemleak结果:catsyskerneldebugkmemleak分析测试结果每处泄露,都标出泄露地址和大小;相关进程信息;内存内容栈回溯。kmemleak会提示内存泄露可疑对象的具体栈调用信息、可疑对象的大小、使用哪个函数分配、二进制打印。unreferencedobject0xede22dc0(size128):第一处可疑泄露128字节comminsmod,pid765,jiffies4294941257(age104。920s)相关进程信息hexdump(first32bytes):二进制打印6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkk6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkkbacktrace:栈回溯〔bf002014〕0xbf002014〔c000973c〕dooneinitcall0x900x1d8〔c00a71f4〕doinitmodule0x600x38c〔c0086898〕loadmodule0x1bac0x1e94〔c0086ccc〕SySinitmodule0x14c0x15c〔c000f3c0〕retfastsyscall0x00x3c〔ffffffff〕0xffffffffunreferencedobject0xf12ba000(size4096):comminsmod,pid765,jiffies4294941257(age104。920s)hexdump(first32bytes):d821000002180000e421000002180000。!。。。。。。。!。。。。。。46220000021800005222000002180000F。。。。。。R。。。。。。backtrace:〔c00d77c8〕vmalloc0x2c0x34〔bf002014〕0xbf002014〔c000973c〕dooneinitcall0x900x1d8〔c00a71f4〕doinitmodule0x600x38c〔c0086898〕loadmodule0x1bac0x1e94〔c0086ccc〕SySinitmodule0x14c0x15c〔c000f3c0〕retfastsyscall0x00x3c〔ffffffff〕0xffffffffkasankasan暂不支持32位ARM,支持ARM64和X86。kasan是一个动态检查内存错误的工具,可以检查内存越界访问、使用已释放内存、重复释放以及栈溢出。使能kasan使用kasan,必须打开CONFIGKASAN。KernelhackingMemorydebuggingKASan:runtimememorydebugger CONFIGHAVEARCHKASANyCONFIGKASANyCONFIGKASANOUTLINEisnotsetCONFIGKASANINLINEyCONFIGTESTKASANm代码分析 kasanreportkasanreporterrorprinterrordescriptionprintaddressdescriptionprintshadowforaddress测试用及分析kasan提供了一个测试程序testkacan。c,将其编译成模块,加载到内核。可以模拟很多内存错误场景。kasan可以检测到越界访问、访问已释放内存、重复释放等类型错误,其中重复释放借助于slubdebug。 insmoddatakasan。ko越界访问包括slab越界、栈越界、全局变量越界;访问已释放内存重复释放可以被slubdebug识别。 slaboutofboundsstaticnoinlinevoidinitkmallocoobright(void){sizetsize123;prinfo(outofboundstoright);ptrkmalloc(size,GFPKERNEL);if(!ptr){prerr(Allocationfailed);}ptr〔size〕x;kfree(ptr);}此种错误类型是对slab的越界访问,包括左侧、右侧、扩大、缩小后越界访问。除了数组赋值,还包括memset、指针访问等等。al:kasanerrortestinitkasantest:kmallocoobrightoutofboundstorightBUG:KASAN:slaboutofboundsinkmallocoobright0xa40xe0〔kasan〕ataddrffff800066539c7b错误类型是slaboutofbounds,在kmallocoobright中产生。Writeofsize1bytaskinsmod788BUGkmalloc128(Tainted:GO):kasan:badaccessdetectedslab非法非法访问DisablinglockdebuggingduetokerneltaintINFO:Allocatedinkmallocoobright0x540xe0〔kasan〕age0cpu1pid788问题点kmallocoobright的栈回溯allocdebugprocessing0x17c0x188slaballoc。constprop。300x3f80x440slaballoc。isra。27。constprop。290x240x38kmemcachealloc0x2200x280kmallocoobright0x540xe0〔kasan〕kmalloctestsinit0x180x70〔kasan〕dooneinitcall0x11c0x310doinitmodule0x1cc0x588loadmodule0x48cc0x5dc0SySinitmodule0x1a80x1e0el0svcnaked0x240x28INFO:Freedindooneinitcall0x10c0x310age0cpu1pid788freedebugprocessing0x17c0x368slabfree0x3440x4a0kfree0x21c0x250dooneinitcall0x10c0x310doinitmodule0x1cc0x588loadmodule0x48cc0x5dc0SySinitmodule0x1a80x1e0el0svcnaked0x240x28INFO:Slab0xffff7bffc2994e00objects16used2fp0xffff800066539e00flags0x4080INFO:Object0xffff800066539c00offset7168fp0xffff800066538200Bytesb4ffff800066539bf0:00000000000000000000000000000000。。。。。。。。。。。。。。。。内存dumpObjectffff800066539c00:008253660080ffff74657374735f696e。。Sf。。。。testsinObjectffff800066539c10:6974205b6b6173616e5d000000000000it〔kasan〕。。。。。。Objectffff800066539c20:00000000000000000000000000000000。。。。。。。。。。。。。。。。Objectffff800066539c30:00000000000000000000000000000000。。。。。。。。。。。。。。。。Objectffff800066539c40:00000000000000000000000000000000。。。。。。。。。。。。。。。。Objectffff800066539c50:00000000000000000000000000000000。。。。。。。。。。。。。。。。Objectffff800066539c60:00000000000000000000000000000000。。。。。。。。。。。。。。。。Objectffff800066539c70:00000000000000000000000000000000。。。。。。。。。。。。。。。。Paddingffff800066539db0:00000000000000000000000000000000。。。。。。。。。。。。。。。。Paddingffff800066539dc0:00000000000000000000000000000000。。。。。。。。。。。。。。。。Paddingffff800066539dd0:00000000000000000000000000000000。。。。。。。。。。。。。。。。Paddingffff800066539de0:00000000000000000000000000000000。。。。。。。。。。。。。。。。Paddingffff800066539df0:00000000000000000000000000000000。。。。。。。。。。。。。。。。CPU:1PID:788Comm:insmodTainted:GBO4。4。0108打印此log消息的栈回溯Hardwarename:linux,dummyvirt(DT)Calltrace:〔ffff80000008e938〕dumpbacktrace0x00x270〔ffff80000008ebbc〕showstack0x140x20〔ffff800000735bb0〕dumpstack0x1000x188〔ffff800000318f60〕printtrailer0xf80x160〔ffff80000031ea8c〕objecterr0x3c0x50〔ffff8000003209a0〕kasanreporterror0x2400x558〔ffff800000320e90〕asanreportstore1noabort0x480x50〔ffff7ffffc008324〕kmallocoobright0xa40xe0〔kasan〕〔ffff7ffffc009070〕kmalloctestsinit0x180x70〔kasan〕〔ffff80000008309c〕dooneinitcall0x11c0x310〔ffff8000002648c4〕doinitmodule0x1cc0x588〔ffff800000206724〕loadmodule0x48cc0x5dc0〔ffff800000207dc0〕SySinitmodule0x1a80x1e0〔ffff800000086cb0〕el0svcnaked0x240x28Memorystatearoundthebuggyaddress:ffff800066539b00:fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcffff800066539b80:fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcffff800066539c00:00000000000000000000000000000003ffff800066539c80:fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcffff800066539d00:fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfc userafterfreeuserafterfree是释放后使用的意思。staticnoinlinevoidinitkmallocuaf(void){sizetsize10;prinfo(useafterfree);ptrkmalloc(size,GFPKERNEL);if(!ptr){prerr(Allocationfailed);}kfree(ptr);(ptr8)x;} 测试结果如下:kasantest:kmallocuafuseafterfreeBUG:KASAN:useafterfreeinkmallocuaf0xac0xe0〔kasan〕ataddrffff800066539e08Writeofsize1bytaskinsmod788BUGkmalloc128(Tainted:GBO):kasan:badaccessdetectedINFO:Allocatedinkmallocuaf0x540xe0〔kasan〕age0cpu1pid788allocdebugprocessing0x17c0x188slaballoc。constprop。300x3f80x440slaballoc。isra。27。constprop。290x240x38kmemcachealloc0x2200x280kmallocuaf0x540xe0〔kasan〕kmalloctestsinit0x480x70〔kasan〕dooneinitcall0x11c0x310doinitmodule0x1cc0x588loadmodule0x48cc0x5dc0SySinitmodule0x1a80x1e0el0svcnaked0x240x28INFO:Freedinkmallocuaf0x840xe0〔kasan〕age0cpu1pid788freedebugprocessing0x17c0x368slabfree0x3440x4a0kfree0x21c0x250kmallocuaf0x840xe0〔kasan〕kmalloctestsinit0x480x70〔kasan〕dooneinitcall0x11c0x310doinitmodule0x1cc0x588loadmodule0x48cc0x5dc0SySinitmodule0x1a80x1e0el0svcnaked0x240x28INFO:Slab0xffff7bffc2994e00objects16used1fp0xffff800066539e00flags0x4080INFO:Object0xffff800066539e00offset7680fp0xffff800066539800Bytesb4ffff800066539df0:00000000000000000000000000000000。。。。。。。。。。。。。。。。Objectffff800066539e00:009853660080ffff0000000000000000。。Sf。。。。。。。。。。。。Objectffff800066539e10:009e53660080ffffd05112000080ffff。。Sf。。。。。Q。。。。。。Objectffff800066539e20:0000000000000000e0146d010080ffff。。。。。。。。。。m。。。。。Objectffff800066539e30:0069a3660080ffff1869a3660080ffff。i。f。。。。。i。f。。。。Objectffff800066539e40:00000000000000000000000000000000。。。。。。。。。。。。。。。。Objectffff800066539e50:30da73000080ffff0069a3660080ffff0。s。。。。。。i。f。。。。Objectffff800066539e60:00000000000000000000000000000000。。。。。。。。。。。。。。。。Objectffff800066539e70:00000000000000000000000000000000。。。。。。。。。。。。。。。。Paddingffff800066539fb0:00000000000000000000000000000000。。。。。。。。。。。。。。。。Paddingffff800066539fc0:00000000000000000000000000000000。。。。。。。。。。。。。。。。Paddingffff800066539fd0:00000000000000000000000000000000。。。。。。。。。。。。。。。。Paddingffff800066539fe0:00000000000000000000000000000000。。。。。。。。。。。。。。。。Paddingffff800066539ff0:00000000000000000000000000000000。。。。。。。。。。。。。。。。CPU:1PID:788Comm:insmodTainted:GBO4。4。0108Hardwarename:linux,dummyvirt(DT)Calltrace:〔ffff80000008e938〕dumpbacktrace0x00x270〔ffff80000008ebbc〕showstack0x140x20〔ffff800000735bb0〕dumpstack0x1000x188〔ffff800000318f60〕printtrailer0xf80x160〔ffff80000031ea8c〕objecterr0x3c0x50〔ffff8000003209a0〕kasanreporterror0x2400x558〔ffff800000320e90〕asanreportstore1noabort0x480x50〔ffff7ffffc00874c〕kmallocuaf0xac0xe0〔kasan〕〔ffff7ffffc0090a0〕kmalloctestsinit0x480x70〔kasan〕〔ffff80000008309c〕dooneinitcall0x11c0x310〔ffff8000002648c4〕doinitmodule0x1cc0x588〔ffff800000206724〕loadmodule0x48cc0x5dc0〔ffff800000207dc0〕SySinitmodule0x1a80x1e0〔ffff800000086cb0〕el0svcnaked0x240x28Memorystatearoundthebuggyaddress:ffff800066539d00:fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcffff800066539d80:fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcffff800066539e00:fbfbfbfbfbfbfbfbfbfbfbfbfbfbfbfbffff800066539e80:fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfcffff800066539f00:fcfcfcfcfcfcfcfcfcfcfcfcfcfcfcfc stackoutofbounds栈越界访问是函数中数组越界,在实际工程中经常出现,问题难以发现。staticnoinlinevoidinitkasanstackoob(void){charstackarray〔10〕;volatileinti0;charpstackarray〔ARRAYSIZE(stackarray)i〕;prinfo(outofboundsonstack);(volatilechar)p;} kasantest:kasanstackooboutofboundsonstackBUG:KASAN:stackoutofboundsinkasanstackoob0xa80xf0〔kasan〕ataddrffff800066acb95aReadofsize1bytaskinsmod788page:ffff7bffc29ab2c0count:0mapcount:0mapping:(null)index:0x0flags:0x0()pagedumpedbecause:kasan:badaccessdetectedCPU:1PID:788Comm:insmodTainted:GBO4。4。0108Hardwarename:linux,dummyvirt(DT)Calltrace:〔ffff80000008e938〕dumpbacktrace0x00x270〔ffff80000008ebbc〕showstack0x140x20〔ffff800000735bb0〕dumpstack0x1000x188〔ffff800000320c90〕kasanreporterror0x5300x558〔ffff800000320d00〕asanreportload1noabort0x480x50〔ffff7ffffc0080a8〕kasanstackoob0xa80xf0〔kasan〕〔ffff7ffffc0090b0〕kmalloctestsinit0x580x70〔kasan〕〔ffff80000008309c〕dooneinitcall0x11c0x310〔ffff8000002648c4〕doinitmodule0x1cc0x588〔ffff800000206724〕loadmodule0x48cc0x5dc0〔ffff800000207dc0〕SySinitmodule0x1a80x1e0〔ffff800000086cb0〕el0svcnaked0x240x28Memorystatearoundthebuggyaddress:ffff800066acb800:00000000000000000000000000000000ffff800066acb880:0000000000000000000000000000f1f1ffff800066acb900:f1f104f4f4f4f2f2f2f20002f4f4f3f3ffff800066acb980:f3f3000000000000000000000000f1f1ffff800066acba00:f1f10000000000000000f3f3f3f30000 globaloutofboundsstaticcharglobalarray〔10〕;staticnoinlinevoidinitkasanglobaloob(void){volatileinti3;charpglobalarray〔ARRAYSIZE(globalarray)i〕;prinfo(outofboundsglobalvariable);(volatilechar)p;} 测试结果如下:kasantest:kasanglobalooboutofboundsglobalvariableBUG:KASAN:globaloutofboundsinkasanglobaloob0x9c0xe8〔kasan〕ataddrffff7ffffc001c8dReadofsize1bytaskinsmod788Addressbelongstovariableglobalarray0xd0xffffffffffffe3f8〔kasan〕CPU:1PID:788Comm:insmodTainted:GBO4。4。0108Hardwarename:linux,dummyvirt(DT)Calltrace:〔ffff80000008e938〕dumpbacktrace0x00x270〔ffff80000008ebbc〕showstack0x140x20〔ffff800000735bb0〕dumpstack0x1000x188〔ffff800000320c90〕kasanreporterror0x5300x558〔ffff800000320d00〕asanreportload1noabort0x480x50〔ffff7ffffc00818c〕kasanglobaloob0x9c0xe8〔kasan〕〔ffff7ffffc0090b4〕kmalloctestsinit0x5c0x70〔kasan〕〔ffff80000008309c〕dooneinitcall0x11c0x310〔ffff8000002648c4〕doinitmodule0x1cc0x588〔ffff800000206724〕loadmodule0x48cc0x5dc0〔ffff800000207dc0〕SySinitmodule0x1a80x1e0〔ffff800000086cb0〕el0svcnaked0x240x28Memorystatearoundthebuggyaddress:ffff7ffffc001b80:00000000000000000000000000000000ffff7ffffc001c00:00000000000000000000000000000000ffff7ffffc001c80:0002fafafafafafa0000000000000000ffff7ffffc001d00:00000000000000000000000000000000ffff7ffffc001d80:00000000000000000000000000000000小结kmemleak检查内存泄露的独门绝技,让其有一定市场空间。但功能比较单一,专注于内存泄露问题。对于非ARM64x86平台,只能使用slubdebug进行内存问题分析;kasan更高效,但也需要更高的内核和GCC版本支持。