From: Tobias Brunner Date: Mon, 8 Jan 2024 15:05:20 +0000 (+0100) Subject: leak-detective: Add implementation of malloc_usable_size() X-Git-Tag: android-2.5.0~23 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=22fc539edd2ddaa9521c6e370d5cc423c32352f5;p=thirdparty%2Fstrongswan.git leak-detective: Add implementation of malloc_usable_size() systemd seems to use this and if we indirectly use libraries provided by it, which can e.g. happen via getgrnam_r() and nss-systemd, this may be called on pointers returned by leak detective's malloc(), which will not point to the original start of the block and cause a segmentation fault. Closes strongswan/strongswan#2045 --- diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index cc7d504c3a..78a8a709f6 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -27,6 +27,7 @@ #endif #include #include +#include #ifdef __APPLE__ #include @@ -288,6 +289,14 @@ static void* real_realloc(void *ptr, size_t size) return original.realloc(malloc_default_zone(), ptr, size); } +/** + * Call original malloc_usable_size() + */ +static size_t real_malloc_usable_size(void *ptr) +{ + return original.size(malloc_default_zone(), ptr); +} + /** * Hook definition: static function with _hook suffix, takes additional zone */ @@ -302,30 +311,7 @@ HOOK(void*, calloc, size_t nmemb, size_t size); HOOK(void*, valloc, size_t size); HOOK(void, free, void *ptr); HOOK(void*, realloc, void *old, size_t bytes); - -/** - * malloc zone size(), must consider the memory header prepended - */ -HOOK(size_t, size, const void *ptr) -{ - bool before; - size_t size; - - if (enabled) - { - before = enable_thread(FALSE); - if (before) - { - ptr -= sizeof(memory_header_t); - } - } - size = original.size(malloc_default_zone(), ptr); - if (enabled) - { - enable_thread(before); - } - return size; -} +HOOK(size_t, malloc_usable_size, void *ptr); /** * Version of malloc zones we currently support @@ -364,7 +350,7 @@ static bool register_hooks() return FALSE; } - zone->size = size_hook; + zone->size = malloc_usable_size_hook; zone->malloc = malloc_hook; zone->calloc = calloc_hook; zone->valloc = valloc_hook; @@ -476,6 +462,20 @@ static void* real_realloc(void *ptr, size_t size) return fn(ptr, size); } +/** + * Call original malloc_usable_size() + */ +static size_t real_malloc_usable_size(void *ptr) +{ + static size_t (*fn)(void *ptr); + + if (!fn) + { + fn = get_malloc_fn("malloc_usable_size"); + } + return fn(ptr); +} + /** * Hook definition: plain function overloading existing malloc calls */ @@ -488,6 +488,8 @@ static bool register_hooks() { void *buf = real_malloc(8); buf = real_realloc(buf, 16); + size_t sz = real_malloc_usable_size(buf); + assert(sz >= 16); real_free(buf); return TRUE; } @@ -1138,6 +1140,69 @@ HOOK(void*, realloc, void *old, size_t bytes) return hdr + 1; } +HOOK(size_t, malloc_usable_size, void *ptr) +{ + memory_header_t *hdr; + memory_tail_t *tail; + size_t sz; + bool before; + + if (!enabled || thread_disabled->get(thread_disabled)) + { + /* after deinitialization we might have to operate on stuff we allocated + * while we were enabled */ + if (!first_header.magic && ptr) + { + hdr = ptr - sizeof(memory_header_t); + tail = ptr + hdr->bytes; + if (hdr->magic == MEMORY_HEADER_MAGIC && + tail->magic == MEMORY_TAIL_MAGIC) + { + return hdr->bytes; + } + } + return real_malloc_usable_size(ptr); + } + if (!ptr) + { + return 0; + } + hdr = ptr - sizeof(memory_header_t); + tail = ptr + hdr->bytes; + + before = enable_thread(FALSE); + if (hdr->magic != MEMORY_HEADER_MAGIC || + tail->magic != MEMORY_TAIL_MAGIC) + { + /* check if memory appears to be allocated by our hooks */ + if (has_hdr(hdr)) + { + if (hdr->magic == MEMORY_HEADER_MAGIC) + { + /* only return the actual size if the header magic is valid */ + sz = hdr->bytes; + } + else + { + /* otherwise use the default function minus our overhead */ + sz = real_malloc_usable_size(hdr); + sz -= sizeof(memory_header_t) + sizeof(memory_tail_t); + } + } + else + { + /* use the default function to determine size of unknown memory */ + sz = real_malloc_usable_size(ptr); + } + } + else + { + sz = hdr->bytes; + } + enable_thread(before); + return sz; +} + METHOD(leak_detective_t, destroy, void, private_leak_detective_t *this) {