glibc malloc保护字节包装器

时间:2014-04-16 11:23:31

标签: c linux memory malloc glibc

我正在尝试在每个已分配的块的最后添加一个保护字符,以便free()可以abort()如果找不到它。为什么这些功能预加载不起作用?我意识到这不是一种便携式方法,但我很好奇为什么它不起作用。

gcc -shared -fPIC -std=gnu99 -O2 -o wrapper.so wrapper.c

LD_PRELOAD=/path/to/wrapper.so programname

我每个都有一个功能:vallocreallocpvallocposix_memalignaligned_allocmemalign,{{1} }和malloc

calloc

1 个答案:

答案 0 :(得分:0)

您正在使用位于分配区域之前的size_t作为可用长度。但是,包含 size_t本身。因此,在这里:

    if (p != NULL) {
        size_t *q = p;
        q--;
        size_t s = *q & ~(SIZE_BITS); // get allocated bytes subtracting info bits
        char *z = p;
        memset(z, 0, s); // zero memory
        z[s - 1] = '@'; // place guard char
    }

你最终会被保护字符覆盖 next 区域的长度。解决方案是以字节为单位减去长度字段的长度,即改为使用const s = (((size_t *)p)[-1] & (~(size_t)SIZE_BITS)) - sizeof (size_t);

(我验证这适用于x86-64上的嵌入式GNU C库2.15-0ubuntu10.15,适用于64位和32位代码(大小不同size_t)。)

我建议您至少添加最少的抽象,以便将来将代码移植到不同的C库或更新版本的GNU C库并非徒劳。 (版本检查会很好,但我太懒了,无法找出哪个版本的GNU C库实际上使用了这种布局。)

#include <string.h>
#include <limits.h>
#ifdef __GLIBC__

/* GLIBC stuffs the length just prior to the returned pointer,
 * with flags in the least significant three bits. It includes
 * the length field itself. */
#define   USER_LEN(ptr) ( ( ((size_t *)(ptr))[-1] & (~((size_t)7)) ) - sizeof (size_t))

#else
#error This C library is not supported (yet).
#endif

extern void  abort(void);
extern void *__libc_malloc(size_t);
extern void *__libc_realloc(void *, size_t);
extern void  __libc_free(void *);


#define CANARY_LEN 1

static void canary_set(void *const ptr, const size_t len)
{
    ((unsigned char *)ptr)[len - CANARY_LEN] = '@';
}

static int canary_ok(const void *const ptr, const size_t len)
{
    return ((const unsigned char *)ptr)[len - CANARY_LEN] == '@';
}


void *malloc(size_t size)
{
    void *ptr;
    ptr = __libc_malloc(size + CANARY_LEN);
    if (ptr) {
        const size_t len = USER_LEN(ptr);
        memset(ptr, 0, len);
        canary_set(ptr, len);
    }
    return ptr;
}

void *realloc(void *ptr, size_t size)
{
    void *newptr;

    if (!ptr)
        return malloc(size);

    if (!canary_ok(ptr, USER_LEN(ptr)))
        abort();

    newptr = __libc_realloc(ptr, size + CANARY_LEN);
    if (!newptr)
        return newptr;

    canary_set(newptr, USER_LEN(ptr));

    return newptr;
}

void free(void *ptr)
{
    if (ptr) {
        const size_t len = USER_LEN(ptr);

        if (!canary_ok(ptr, len))
            abort();

        memset(ptr, 0, len);

        __libc_free(ptr);
    }
}

希望这有帮助。