1. 程式人生 > >用slub track除錯use after free問題

用slub track除錯use after free問題

宕機重啟問題中,有部分是訪問了已釋放的記憶體導致,這就是典型的userafter free問題.

開啟CONFIG_SLUB_DEBUGCONFIG_SLUB_DEBUG_ON巨集開關後,系統就可以監測記憶體的釋放與分配呼叫棧.

 

1. slab 記憶體佈局

slub的記憶體管理原理這裡就不在詳述.直接給出slabobject物件的記憶體佈局,object記憶體包含下面四個部分:

object_size +Redzone + Freepointer +2*track+pading

object_size :待分配記憶體的大小,alloc時為0x5a,free後為

0x6b,但是最後一個Byte0xa5表示object的結束,之後的資料都為metadata.

Redzone : 標記區.alloc填充0xcc,free後填充0bb

Freepointer :指向下一個空閒的object

2structtrack結構,用於跟蹤記憶體的分配與釋放棧

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的記憶體佈局,很容易找到alloctrackfreetrack的地址,再用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的呼叫棧。