用slub track除錯use after free問題
宕機重啟問題中,有部分是訪問了已釋放的記憶體導致,這就是典型的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後為
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的呼叫棧。