• 用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后为0x6b,但是最后一个Byte为0xa5表示object的结束,之后的数据都为metadata.

    Redzone : 标记区.alloc填充0xcc,free后填充0bb

    Freepointer :指向下一个空闲的object

    2个structtrack结构,用于跟踪内存的分配与释放栈

    pading :填充区,为了内存对齐,填充为0x5a

    典型的object内存布局

    slub info

    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

  • 相关阅读:
    Flask 中的路由系统
    Flask 中内置的 Session
    Flask中的模板语言jinja2
    Flask 中的 5种返回值
    Redis快速入门
    动态实现前后台分页、翻页按钮、上一页、下一页、首页、末页
    bus.js非父子组件之间通讯
    vue中父子组件之间相互传值
    js实现加减乘除
    禁用微信分享
  • 原文地址:https://www.cnblogs.com/smilingsusu/p/14479938.html
Copyright © 2020-2023  润新知