Linux内核SLUB调试日志分析:如何定位0x90000001048adce8地址?
Linux内核SLUB调试:非法地址访问与游离内存对象定位
问题背景
我在Linux内核调试过程中遇到非法地址访问问题,启用SLUB调试后得到以下日志信息:
[ 5.122249] ============================================================================= [ 5.130490] BUG kmalloc-8 (Not tainted): Freepointer corrupt [ 5.136184] ----------------------------------------------------------------------------- [ 5.136184] [ 5.145914] Allocated in mmc_app_send_scr+0xe8/0x1e0 age=11 cpu=1 pid=24 [ 5.152678] kmalloc_trace_noprof+0x128/0x340 [ 5.157081] mmc_app_send_scr+0xe4/0x1e0 [ 5.161039] mmc_sd_setup_card+0x154/0x640 [ 5.165171] mmc_sd_init_card+0x15c/0xcc0 [ 5.169214] mmc_attach_sd+0x10c/0x220 [ 5.172998] mmc_rescan+0x37c/0x4a0 [ 5.176526] process_one_work+0x17c/0x320 [ 5.180575] worker_thread+0x384/0x4e0 [ 5.184358] kthread+0x13c/0x160 [ 5.187620] ret_from_kernel_thread+0x8/0xa4 [ 5.191925] Freed in mpi_free+0x34/0xa0 age=44 cpu=0 pid=100 [ 5.197628] mpi_free+0x30/0xa0 [ 5.200797] rsa_dec+0x188/0x260 [ 5.204061] test_akcipher_one+0x758/0x8c0 [ 5.208194] alg_test_akcipher+0xa8/0x140 [ 5.212239] alg_test+0x180/0x780 [ 5.215586] cryptomgr_test+0x1c/0x40 [ 5.219281] kthread+0x13c/0x160 [ 5.222539] ret_from_kernel_thread+0x8/0xa4 [ 5.226843] Slab 0xffffffff01048ac0 objects=146 used=67 fp=0x90000001048add58 flags=0x1ffff0000000200(workingset|node=0|zone=1|lastcpupid=0xffff) [ 5.239968] Object 0x90000001048adce8 @offset=7400 fp=0x00000000048add58 [ 5.239968] [ 5.248206] Redzone 90000001048adce0: cc cc cc cc cc cc cc cc ........ [ 5.257052] Object 90000001048adce8: 00 00 a5 02 6b 6b 6b a5 ....kkk. [ 5.265897] Redzone 90000001048adcf0: cc cc cc cc cc cc cc cc ........ [ 5.274741] Padding 90000001048add44: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZ [ 5.283935] CPU: 1 PID: 24 Comm: kworker/1:0 Not tainted 6.10.0-rc1+ #5998 [ 5.290853] Workqueue: events_freezable mmc_rescan [ 5.295695] Stack : 90000001000993b0 0000000000000000 9000000002db37e4 9000000100298000 [ 5.303778] 900000010029b800 900000010029b808 0000000000000000 0000000000000000 [ 5.311856] 900000010029b808 0000000000000001 900000018029b527 900000010029b3b0 [ 5.319934] ffffffffffffffff 900000010029b808 5404302515683bd9 9000000100239040 [ 5.328012] 000000000000024f 0000000000000001 0000000000000000 0000000000000003 [ 5.336090] 0000000000000b54 0000000000047025 0000000008d6c000 90000000057b4000 [ 5.344168] 0000000000000000 0000000000000000 9000000004994fb8 9000000004b25000 [ 5.352245] 0000000000000000 90000001048adcf0 0000000000000001 9000000100004640 [ 5.360321] 90000001048adce8 0000000000000000 9000000002db3804 ffffff80141ac4a2 [ 5.368399] 00000000000000b0 0000000000000004 0000000000000000 0000000000071c1d [ 5.376476] ... [ 5.378950] Call Trace: [ 5.378955] [<9000000002db3804>] show_stack+0x64/0x1a0 [ 5.386599] [<90000000041e8c74>] dump_stack_lvl+0x74/0xb0 [ 5.392043] [<90000000041ce578>] object_err+0x3c/0x60 [ 5.397141] [<90000000030484f4>] check_object+0x4b4/0x4e0 [ 5.402583] [<9000000003048e34>] free_to_partial_list+0x1f4/0x6a0 [ 5.408721] [<9000000003049c08>] kfree+0x188/0x340 [ 5.413552] [<9000000003d9e564>] mmc_app_send_scr+0x184/0x1e0 [ 5.419341] [<9000000003d9c5f4>] mmc_sd_setup_card+0x154/0x640 [ 5.425216] [<9000000003d9cc3c>] mmc_sd_init_card+0x15c/0xcc0 [ 5.431004] [<9000000003d9da4c>] mmc_attach_sd+0x10c/0x220 [ 5.436530] [<9000000003d9177c>] mmc_rescan+0x37c/0x4a0 [ 5.441797] [<9000000002dfa5bc>] process_one_work+0x17c/0x320 [ 5.447586] [<9000000002dfb304>] worker_thread+0x384/0x4e0 [ 5.453113] [<9000000002e06abc>] kthread+0x13c/0x160 [ 5.458117] [<9000000002db14a4>] ret_from_kernel_thread+0x8/0xa4 [ 5.464164] [ 5.465674] Disabling lock debugging due to kernel taint [ 5.471016] FIX kmalloc-8: Object at 0x90000001048adce8 not freed
日志中记录的内存分配函数mmc_app_send_scr()与释放函数mpi_free()并无关联,分析这两个函数未找到有效线索,求助如何定位地址0x90000001048adce8的问题根源。
定位方法
1. 确认内存对象的生命周期异常类型
从日志看,这是典型的内存重复释放/野指针写导致的freepointer损坏:
- 分配在
mmc_app_send_scr,但释放时被mpi_free操作,说明该对象的内存块被错误地标记为属于MPI子系统的内存,大概率是某个地方出现了指针越界,覆盖了SLUB的freepointer字段,或者该内存块被提前释放后又被复用,同时被两个子系统操作。
2. 直接定位内存地址的操作轨迹
- 启用SLUB的
trace功能:启动内核时添加参数slub_debug=trace,kmalloc-8,这样会记录该slab中每个对象的分配、释放、修改轨迹,能直接看到0x90000001048adce8被哪些函数访问过。 - 使用
gdb调试内核:- 若能复现问题,在崩溃时暂停内核,执行
x/16x 0x90000001048adce8查看内存内容,对比SLUB日志中的对象数据(00 00 a5 02 6b 6b 6b a5),确认是否有异常修改。 - 查看该地址所在的slab信息:执行
p slab_info(0x90000001048adce8),可以获取更多slab和对象的元数据。
- 若能复现问题,在崩溃时暂停内核,执行
- 启用内存访问检测:
- 开启
CONFIG_KASAN(地址 sanitizer),它能精准捕捉到非法内存访问的发生点,比SLUB调试更直接定位越界写的位置。 - 若内核版本支持,开启
CONFIG_SLUB_DEBUG_ON和CONFIG_SLUB_DEBUG的所有子选项,尤其是CONFIG_SLUB_STATS和CONFIG_SLUB_DEBUG_FREE,能提供更详细的内存操作记录。
- 开启
3. 交叉验证两个调用链的关联性
虽然mmc_app_send_scr和mpi_free看似无关,但可能存在以下隐藏关联:
- 检查是否有共享的内存池或全局缓冲区被两个子系统同时使用,比如某个DMA缓冲区、全局临时内存块被错误复用。
- 查看
mpi_free中释放的内存块是否和mmc_app_send_scr分配的内存块大小一致(都是8字节,kmalloc-8),确认是否是SLUB分配器的复用机制导致的对象混淆,此时需要检查是否有内存释放后未置空指针,导致野指针访问。
4. 针对性代码审计
- 审计
mmc_app_send_scr:检查它分配的8字节内存是否被正确传递、使用,是否存在越界写(比如写入超过8字节的数据),是否在释放前就被其他代码修改。 - 审计
mpi_free:检查它处理的指针是否合法,是否存在将非MPI分配的内存传入释放函数的情况,比如指针被错误赋值、类型转换错误。
内容的提问来源于stack exchange,提问作者Aaron Chou
相关产品推荐
相关产品推荐

