死机重启问题中,有部分是访问了已释放的内存导致,这就是典型的userafter free问题.
打开CONFIG_SLUB_DEBUG和CONFIG_SLUB_DEBUG_ON宏开关后,系统就可以监测内存的释放与分配调用栈.
1. slab 内存布局
slub的内存管理原理这里就不在详述.直接给出slabobject对象的内存布局,object内存包含下面四个部分:
object_size +Redzone + Freepointer +2*track+pading
object_size :待分配内存的大小,alloc时为0x5a,free后为0x6b,但是最后一个Byte为0xa5表示object的结束,之后的数据都为metadata.
Redzone : 标记区.alloc填充0xcc,free后填充0bb
Freepointer :指向下一个空闲的object
2个structtrack结构,用于跟踪内存的分配与释放栈
pading :填充区,为了内存对齐,填充为0x5a
典型的object内存布局
2. 相关变量
kmem_cache->inuse= object_size + Redzone
kmem_cache->offset= inuse or =0
kmem_cache->size= object_size +Redzone+Freepointer+2*track+pading
3. 查找track信息
当系统出现KE时,用gdb调试打印内存,发现访问的内存全变成了0x6b,则可以怀疑是userafter free。
分析下述案例:
crash_arm64> musb_qh 0xffffffc0640ebc80 -x
struct musb_qh {
hep = 0x6b6b6b6b6b6b6b6b,
dev = 0x6b6b6b6b6b6b6b6b,
这个地址0xffffffc0640ebc80出问题了,下面看是slub分配的,所以可以用slub track分析了。
crash_arm64> kmem 0xffffffc0640ebc80
CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE
ffffffc079007980 kmalloc-256 256 5184 5208 248 16k
SLAB MEMORY NODE TOTAL ALLOCATED FREE
ffffffbdc1903a00 ffffffc0640e8000 0 21 19 2
FREE / [ALLOCATED]
[ffffffc0640ebc00]
PAGE PHYSICAL MAPPING INDEX CNT FLAGS
ffffffbdc1903ac0 e40eb000 0 1 0 0
struct kmem_cache {
cpu_slab = 0xffffff8008e6bc30,
flags = 0x80010d00,
crash_arm64> p kmalloc_caches -x
kmalloc_caches = $1 =
{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffffffc079004380, 0xffffffc079007980, 0xffffffc079004680, 0xffffffc079007680, 0xffffffc079004980, 0xffffffc079007380, 0xffffffc079004c80}
struct kmem_cache {
cpu_slab = 0xffffff8008e6bc30,
flags = 0x80010d00, //这个flag 表明当前debug等级信息,
min_partial = 0x5,
size = 0x300,
object_size = 0x100,
offset = 0x108,
cpu_partial = 0x0,
oo = {
x = 0x20015
},
max = {
x = 0x20015
},
min = {
x = 0x5
},
allocflags = 0x4000,
refcount = 0x1,
ctor = 0x0,
inuse = 0x108,
align = 0x80,
reserved = 0x0,
name = 0xffffff8008c8ef4f "kmalloc-256",
/*
* Flags to pass to kmem_cache_create().
* The ones marked DEBUG are only valid if CONFIG_DEBUG_SLAB is set.
*/
#define SLAB_DEBUG_FREE 0x00000100UL /* DEBUG: Perform (expensive) checks on free */
#define SLAB_RED_ZONE 0x00000400UL /* DEBUG: Red zone objs in a cache */
#define SLAB_POISON 0x00000800UL /* DEBUG: Poison objects */
#define SLAB_HWCACHE_ALIGN 0x00002000UL /* Align objs on cache lines */
#define SLAB_CACHE_DMA 0x00004000UL /* Use GFP_DMA memory */
#define SLAB_STORE_USER 0x00010000UL /* DEBUG: Store the last owner for bug hunting */
#define SLAB_PANIC 0x00040000UL /* Panic if kmem_cache_create() fails */
这里slub track 就是需要SLAB_STORE_USER 这个flag,满足条件。 此slub 肯定包含了alloc和free的track。
分析内存里object的内存布局,找到这个track地址:
ffffffc0640ebbd0: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebbe0: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebbf0: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebc00: bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb ................
ffffffc0640ebc10: bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb ................
ffffffc0640ebc20: bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb ................
ffffffc0640ebc30: bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb ................
ffffffc0640ebc40: bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb ................
ffffffc0640ebc50: bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb ................
ffffffc0640ebc60: bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb ................
ffffffc0640ebc70: bbbbbbbbbbbbbbbb bbbbbbbbbbbbbbbb ................
ffffffc0640ebc80: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebc90: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebca0: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebcb0: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebcc0: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebcd0: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebce0: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebcf0: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebd00: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebd10: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebd20: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebd30: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebd40: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebd50: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebd60: 6b6b6b6b6b6b6b6b 6b6b6b6b6b6b6b6b kkkkkkkkkkkkkkkk
ffffffc0640ebd70: 6b6b6b6b6b6b6b6b a56b6b6b6b6b6b6b kkkkkkkkkkkkkkk.
ffffffc0640ebd80: bbbbbbbbbbbbbbbb ffffffc0640eb680 ...........d.... //used after free的slub好像一般都有这些信息。
ffffffc0640ebd90: ffffff80085e3724 ffffff80081cb79c $7^.............
ffffffc0640ebda0: ffffff80081cbe6c ffffff80081cbf58 l.......X.......
ffffffc0640ebdb0: ffffff80081cc27c ffffff80085e3724 |.......$7^.....
ffffffc0640ebdc0: ffffff800859d374 ffffff800859e7c4 t.Y.......Y.....
ffffffc0640ebdd0: ffffff80087a37f8 ffffff80087ac584 .7z.......z.....
ffffffc0640ebde0: ffffff80087ae554 ffffff80087932cc T.z......2y.....
ffffffc0640ebdf0: ffffff8008792d3c ffffff8008795bd8 <-y......[y.....
ffffffc0640ebe00: ffffff8008796778 ffffff8008797200 xgy......ry.....
ffffffc0640ebe10: ffffff800822ee1c 000003a200000003 ..".............
ffffffc0640ebe20: 000000010028dde4 ffffff80085e3250 ..(.....P2^.....
ffffffc0640ebe30: ffffff80081cd008 ffffff80081cd18c ................
ffffffc0640ebe40: ffffff80081cdec0 ffffff80085e3250 ........P2^.....
ffffffc0640ebe50: ffffff800859d530 ffffff800859e27c 0.Y.....|.Y.....
ffffffc0640ebe60: ffffff80087a29e4 ffffff80087a39f8 .)z......9z.....
ffffffc0640ebe70: ffffff80087ad5d0 ffffff80087ad730 ..z.....0.z.....
ffffffc0640ebe80: ffffff8008792fb8 ffffff8008792d3c ./y.....<-y.....
ffffffc0640ebe90: ffffff8008792dc8 ffffff8008792ec4 .-y.......y.....
ffffffc0640ebea0: ffffff8008794d70 ffffff8008794dbc pMy......My.....
ffffffc0640ebeb0: 00000dfc00000003 000000010028df1a ..........(..... //大致一看cpu和pid就是他了
ffffffc0640ebec0: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebed0: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebee0: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebef0: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebf00: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebf10: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebf20: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebf30: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebf40: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebf50: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebf60: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebf70: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
ffffffc0640ebf80: 5a5a5a5a5a5a5a5a 5a5a5a5a5a5a5a5a ZZZZZZZZZZZZZZZZ
从内存中查找关键字0xa5,0xbb,再参考slabobject的内存布局,很容易找到alloctrack和freetrack的地址,再用gdb打印出内存
crash_arm64> track -ox
struct track {
[0x0] unsigned long addr;
[0x8] unsigned long addrs[16];
[0x88] int cpu;
[0x8c] int pid;
[0x90] unsigned long when;
}
SIZE: 0x98
crash_arm64> track ffffffc0640ebe28 -x
struct track {
addr = 0xffffff80085e3250,
addrs = {0xffffff80081cd008, 0xffffff80081cd18c, 0xffffff80081cdec0, 0xffffff80085e3250, 0xffffff800859d530, 0xffffff800859e27c, 0xffffff80087a29e4, 0xffffff80087a39f8, 0xffffff80087ad5d0, 0xffffff80087ad730, 0xffffff8008792fb8, 0xffffff8008792d3c, 0xffffff8008792dc8, 0xffffff8008792ec4, 0xffffff8008794d70, 0xffffff8008794dbc},
cpu = 0x3,
pid = 0xdfc,
when = 0x10028df1a
}
dis这些地址就知道是谁释放的了。也可以看alloc的调用栈。
————————————————
版权声明:本文为CSDN博主「chenpuo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/chenpuo/article/details/80885789