Glibc-2.29 新增的防护机制

TOC

  1. 1. free
    1. 1.1. tcache
    2. 1.2. chunk extend
  2. 2. malloc
    1. 2.1. unsorted bin
    2. 2.2. top chunk

下面我介绍几种在 glibc-2.29 中增加的防护机制,由于本人才疏学浅, 可能仅是冰山一角。

文章对照的是 glibc-2.27 和 glibc-2.29 。

free

tcache

最明显的就是tcache

来自源码:glibc-2.29/malloc/malloc.c:4197

/* This test succeeds on double free.  However, we don't 100%
trust it (it also matches random payload data at a 1 in
2^<size_t> chance), so verify it's not an unlikely
coincidence before aborting. */
if (__glibc_unlikely (e->key == tcache))
{
tcache_entry *tmp;
LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
for (tmp = tcache->entries[tc_idx];
tmp;
tmp = tmp->next)
if (tmp == e)
malloc_printerr ("free(): double free detected in tcache 2");
/* If we get here, it was a coincidence. We've wasted a
few cycles, but don't abort. */
}

这里会对tcache链表上的所有chunk进行对比,检测是否有重复,这让原本在glibc-2.27glibc-2.28肆虐的tcache double free攻击很难实施,但是鉴于tcache的特性,tcache的利用还是要比其他的bins方便很多。

chunk extend

chunk extend也是很好用的攻击方式之一,但是在glibc-2.29中增加了新的检查,这将会增大chunk extend的难度。

来自源码:glibc-2.29/malloc/malloc.c:4334

/* consolidate backward */
if (!prev_inuse(p)) {
prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
if (__glibc_unlikely (chunksize(p) != prevsize))
malloc_printerr ("corrupted size vs. prev_size while consolidating");
unlink_chunk (av, p);
}

glibc-2.29中新增了prevsize的检查机制,在合并的时候会判断prev_size和要合并chunksize是否相同。

malloc

unsorted bin

原本这里仅仅有size检查。

来自源码:glibc-2.29/malloc/malloc.c:3742

bck = victim->bk;
size = chunksize (victim);
mchunkptr next = chunk_at_offset (victim, size);

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)");

然后在glibc-2.29中,增加了如下检查:

  1. 对下一个相邻chunk的size检查
  2. 对下一个相邻chunk的prev_size进行检查
  3. 检查unsorted bin双向链表的完整性,对unsorted bin attack可以说是很致命的检查
  4. 对下一个chunk的prev_inuse位进行检查

这么多的检查,将使得unsorted bin更难利用。

下面这个检查早在glibc-2.28就有了,这里提一下,主要是防护unsorted bin attack

来自源码:glibc-2.29/malloc/malloc.c:3976

/* remove from unsorted list */
if (__glibc_unlikely (bck->fd != victim))
malloc_printerr ("malloc(): corrupted unsorted chunks 3");
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);

top chunk

对于top chunk增加了size检查,遏制了House of Force攻击。

来自源码:glibc-2.29/malloc/malloc.c:4111

victim = av->top;
size = chunksize (victim);

if (__glibc_unlikely (size > av->system_mem))
malloc_printerr ("malloc(): corrupted top size");