Commit message: bionic: fix integer overflows in chk_malloc(), leak_malloc(), and leak_memalign()

The allocation size in chk_malloc(), leak_malloc(), and leak_memalign()
functions may be rounded up to a small value, leading to buffer overflows.
The code only runs in debugging mode.

This patch complements commit 6f04a0f4 (CVE-2009-0607).

Change-Id: Id899bcd2bcd2ea2205e5753c433390710032dc83
Signed-off-by: Xi Wang <xi.wang@gmail.com>
CVE: CVE-2012-2674
CWE: CWE-189
Vulnerability description: Multiple integer overflows in the (1) chk_malloc, (2) leak_malloc, and (3) leak_memalign functions in libc/bionic/malloc_debug_leak.c in Bionic (libc) for Android, when libc.debug.malloc is set, make it easier for context-dependent attackers to perform memory-related attacks such as buffer overflows via a large size value, which causes less memory to be allocated than expected.

Project: platform_bionic

void* leak_malloc(size_t bytes)
{
    // allocate enough space infront of the allocation to store the pointer for
    // the alloc structure. This will making free'ing the structer really fast!

    // 1. allocate enough memory and include our header
    // 2. set the base pointer to be right after our header

    void* base = dlmalloc(bytes + sizeof(AllocationEntry));
    if (base != NULL) {
        pthread_mutex_lock(&gAllocationsMutex);

            intptr_t backtrace[BACKTRACE_SIZE];
            size_t numEntries = get_backtrace(backtrace, BACKTRACE_SIZE);

            AllocationEntry* header = (AllocationEntry*)base;
            header->entry = record_backtrace(backtrace, numEntries, bytes);
            header->guard = GUARD;

            // now increment base to point to after our header.
            // this should just work since our header is 8 bytes.
            base = (AllocationEntry*)base + 1;

        pthread_mutex_unlock(&gAllocationsMutex);
    }

    return base;
}

Project: platform_bionic

void* chk_malloc(size_t bytes)
{
    char* buffer = (char*)dlmalloc(bytes + CHK_OVERHEAD_SIZE);
    if (buffer) {
        memset(buffer, CHK_SENTINEL_VALUE, bytes + CHK_OVERHEAD_SIZE);
        size_t offset = dlmalloc_usable_size(buffer) - sizeof(size_t);
        *(size_t *)(buffer + offset) = bytes;
        buffer += CHK_SENTINEL_HEAD_SIZE;
    }
    return buffer;
}

Project: platform_bionic

void* leak_memalign(size_t alignment, size_t bytes)
{
    // we can just use malloc
    if (alignment <= MALLOC_ALIGNMENT)
        return leak_malloc(bytes);

    // need to make sure it's a power of two
    if (alignment & (alignment-1))
        alignment = 1L << (31 - __builtin_clz(alignment));

    // here, aligment is at least MALLOC_ALIGNMENT<<1 bytes
    // we will align by at least MALLOC_ALIGNMENT bytes
    // and at most alignment-MALLOC_ALIGNMENT bytes
    size_t size = (alignment-MALLOC_ALIGNMENT) + bytes;
    void* base = leak_malloc(size);
    if (base != NULL) {
        intptr_t ptr = (intptr_t)base;
        if ((ptr % alignment) == 0)
            return base;

        // align the pointer
        ptr += ((-ptr) % alignment);

        // there is always enough space for the base pointer and the guard
        ((void**)ptr)[-1] = MEMALIGN_GUARD;
        ((void**)ptr)[-2] = base;

        return (void*)ptr;
    }
    return base;
}