0%

glibc源码分析

glibc

最近在看malloc的源码,因此记录一下各主流版本之间的差别。

glibc-2.27

  • 2.27增加了tcache

  • 在malloc_consolidate中

    1
    2
    /*新增:检查从fastbin中取出的chunk的大小是否满足fastbin的索引,house-of-rabbit无法使用  */
    unsigned int idx = fastbin_index (chunksize (p));
  • 在unlink中

    1
    2
    3
    /*新增:检查其下一个chunk的prev_size是否和size相等,即使用house-of-einherjar时第一个chunk应该被放入到unsortedbin中*/
    if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0))
    malloc_printerr ("corrupted size vs. prev_size");

glibc-2.29

  • tcache_entry结构体中增加了key,防止doublefree

    1
    2
    3
    4
    5
    6
    typedef struct tcache_entry
    {
    struct tcache_entry *next;
    /* This field exists to detect double frees. */
    struct tcache_perthread_struct *key;
    } tcache_entry;
  • 对在unsortedbin中即将取出的chunk和其nextchunk做检查

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /*新增:unsortedbin attack失效,house-of-storm无法使用*/
    if (__glibc_unlikely (size <= 2 * SIZE_SZ)
    || __glibc_unlikely (size > av->system_mem))
    malloc_printerr ("malloc(): invalid size (unsorted)");
    if (__glibc_unlikely (chunksize_nomask (next) < 2 * SIZE_SZ)
    || __glibc_unlikely (chunksize_nomask (next) > av->system_mem))
    malloc_printerr ("malloc(): invalid next size (unsorted)");
    if (__glibc_unlikely ((prev_size (next) & ~(SIZE_BITS)) != size))
    malloc_printerr ("malloc(): mismatching next->prev_size(unsorted)");
    if (__glibc_unlikely (bck->fd != victim)
    || __glibc_unlikely (victim->fd != unsorted_chunks (av)))
    malloc_printerr ("malloc(): unsorted double linked list corrupted");
    if (__glibc_unlikely (prev_inuse (next)))
    malloc_printerr ("malloc(): invalid next->prev_inuse (unsorted)");
  • 在unlink前增加了对prev_size和size的判断

    1
    2
    /*新增:检查了prev_size和上一个chunk的size是否相等,house-of-einherjar不能使用*/
    if (__glibc_unlikely (chunksize(p) != prevsize))

glibc-2.30&glibc-2.31

  • tcache_perthread_struct中的counts类型变为uint16_t类型

    1
    2
    3
    4
    5
    typedef struct tcache_perthread_struct
    {
    uint16_t counts[TCACHE_MAX_BINS];
    tcache_entry *entries[TCACHE_MAX_BINS];
    } tcache_perthread_struct;
  • 如果tcache->counts[tc_idx]<=0则不会从tcache中取chunk

    1
    2
    3
    4
    5
    6
    if (tc_idx < mp_.tcache_bins
    && tcache
    && tcache->counts[tc_idx] > 0)
    {
    return tcache_get (tc_idx);
    }
  • 将chunk从unsortedbin中取出放入到largebin时做了检查,增大了largebin attack的难度。

    1
    2
    3
    4
    if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd))
    malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)");
    if (bck->fd != fwd)
    malloc_printerr ("malloc(): largebin double linked list corrupted (bk)");

glibc-2.32

  • tcache中对e->next也就是fd指针做了加密,(&e->next>>12)<<12即为heap_base

    1
    2
    3
    e->next = PROTECT_PTR (&e->next, tcache->entries[tc_idx]);
    #define PROTECT_PTR(pos, ptr)
    ((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))
  • 对fastbin的fd指针也做了相同的加密。

    1
    2
    /*新增:fastbin的fd指针被加密*/
    p->fd = PROTECT_PTR (&p->fd, old);
  • 增加了很多指针是否对齐的检查