c-glibc malloc保护字节包装器



我正试图在每个分配的块的末尾添加一个保护字符,以便free()在找不到它的情况下可以abort()。为什么这些函数预加载不起作用?我意识到这不是一个可移植的方法,但我很好奇为什么它不起作用。

gcc -shared -fPIC -std=gnu99 -O2 -o wrapper.so wrapper.c
LD_PRELOAD=/path/to/wrapper.so programname

我每个都有一个函数:vallocreallocpvallocposix_memalignaligned_allocmemalignmalloccalloc

#define PREV_INUSE 0x1
#define IS_MMAPPED 0x2
#define NON_MAIN_ARENA 0x4
#define SIZE_BITS (PREV_INUSE|IS_MMAPPED|NON_MAIN_ARENA)

extern void *__libc_malloc(size_t size);
void *malloc(size_t size){
    size = size + 1; // add char for guard byte '@'
    void *p = __libc_malloc(size);
    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
    }
    return p;
}
extern void *__libc_free(void *ptr);
void free(void *ptr){
    if(ptr != NULL){
        size_t *p = ptr;
        p--;
        size_t s = *p & ~(SIZE_BITS);
        char *z = ptr;
        if(z[s - 1] != '@') // if guard char not found, abort()
        {
            abort();
        }
        memset(z, 0, s); // zero memory
    }
    __libc_free(ptr);
}

您正在使用位于分配区域之前的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
    }

您最终会覆盖下一个区域的长度,部分由您的guard-char覆盖。解决方案是用字节减去长度字段的长度,即使用const s = (((size_t *)p)[-1] & (~(size_t)SIZE_BITS)) - sizeof (size_t);

(我在x86-64上的嵌入式GNU C库2.15-0ubuntu1015上验证了这一点,适用于64位和32位代码(具有不同的size_t大小)。)

我建议您至少添加最低限度的抽象,这样将来将代码移植到不同的C库或GNU C库的新版本中就不会是徒劳的。(版本检查会很好,但我太懒了,没有发现GNUC库的哪些版本真正使用了这种布局。)

#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);
    }
}

希望这能有所帮助。

相关内容

  • 没有找到相关文章

最新更新