From 8a7d5804bcf5ccd66064d654f7c060a220fd5afc Mon Sep 17 00:00:00 2001 From: daan Date: Mon, 6 Apr 2020 16:10:43 -0700 Subject: [PATCH] add corrupted block scanning on overflow detection --- src/alloc.c | 39 ++++++++++++++++++++++++++++++++++--- src/options.c | 23 ++++++++++++---------- test/main-override-static.c | 19 +++++++++++++++++- 3 files changed, 67 insertions(+), 14 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 62445040..fbd88166 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -202,6 +202,8 @@ static inline bool mi_check_is_double_free(const mi_page_t* page, const mi_block // --------------------------------------------------------------------------- #if defined(MI_PADDING) && defined(MI_ENCODE_FREELIST) +static void mi_check_padding(const mi_page_t* page, const mi_block_t* block); + static bool mi_page_decode_padding(const mi_page_t* page, const mi_block_t* block, size_t* delta, size_t* bsize) { *bsize = mi_page_usable_block_size(page); const mi_padding_t* const padding = (mi_padding_t*)((uint8_t*)block + *bsize); @@ -242,9 +244,40 @@ static void mi_check_padding(const mi_page_t* page, const mi_block_t* block) { size_t size; size_t wrong; if (!mi_verify_padding(page,block,&size,&wrong)) { - char msg[80]; - snprintf(msg, 79, "buffer overflow in heap block (write after %zu bytes)", (wrong > 0 ? wrong - 1 : wrong)); - _mi_page_block_error_message(EFAULT, page, block, msg ); + char msg[128]; + snprintf(msg, 127, "buffer overflow in heap block (write after > %zu bytes), at", wrong); + _mi_page_block_error_message(0, page, block, msg ); + // Get page info + const mi_segment_t* segment = _mi_page_segment(page); + size_t psize; + const mi_block_t* first = (mi_block_t*)_mi_page_start(segment, page, &psize); + const size_t bsize = mi_page_block_size(page); // full block size including padding + const mi_block_t* last = (mi_block_t*)((uint8_t*)first + (bsize*page->capacity)); + #define MI_BLOCK_REL(blk,n) ((mi_block_t*)((uint8_t*)(blk) + ((n)*bsize))) + // search down from this block to the first one that is not corrupted + const mi_block_t* low; + size_t size2; + size_t wrong2; + for (low = MI_BLOCK_REL(block, -1); low >= first; low = MI_BLOCK_REL(low, -1)) { + if (mi_verify_padding(page, low, &size2, &wrong2)) break; + } + if (low < MI_BLOCK_REL(block,-1)) { + snprintf(msg, 127, "the overflow may have originated earlier (write after > %zu bytes), from", wrong + (((uint8_t*)block - (uint8_t*)low)) - bsize); + _mi_page_block_error_message(0, page, low, msg); + } + else { + low = MI_BLOCK_REL(block,-1); + } + // search upward to last uncorrupted block + const mi_block_t* hi; + for (hi = MI_BLOCK_REL(block,1); hi < last; hi = MI_BLOCK_REL(hi, 1)) { + if (mi_verify_padding(page, hi, &size, &wrong)) break; + } + if (hi > (MI_BLOCK_REL(block, 1))) { + snprintf(msg, 127, "the overflow may have spanned further (write after > %zu bytes), upto", ((uint8_t*)hi - (uint8_t*)low) - bsize); + _mi_page_block_error_message(0, page, hi, msg); + } + _mi_error_message(EFAULT,NULL); } } diff --git a/src/options.c b/src/options.c index fbf677c8..7cb9e257 100644 --- a/src/options.c +++ b/src/options.c @@ -363,6 +363,7 @@ void mi_register_error(mi_error_fun* fun, void* arg) { } static void mi_call_error_handler(int err) { + if (err == 0) return; if (mi_error_handler != NULL) { mi_error_handler(err, mi_atomic_read_ptr(void, &mi_error_arg)); } @@ -372,11 +373,13 @@ static void mi_call_error_handler(int err) { } void _mi_error_message(int err, const char* fmt, ...) { - // show detailed error message - va_list args; - va_start(args, fmt); - mi_vshow_error_message(fmt, args); - va_end(args); + if (fmt != NULL) { + // show detailed error message + va_list args; + va_start(args, fmt); + mi_vshow_error_message(fmt, args); + va_end(args); + } // and call the error handler which may abort (or return normally) mi_call_error_handler(err); } @@ -436,20 +439,20 @@ void _mi_page_block_error_message(int err, const mi_page_t* page, const mi_block void* return_addr = mi_source_unpack(padding->source, &fname, &lineno); if (return_addr != NULL) { #ifdef _MSC_VER - const char* hint = " hint: paste the code address in the disassembly window in the debugger to find the source location.\n"; + const char* hint = " hint: paste the 'allocated at' address in the disassembly window in the debugger to find the source location.\n"; #else const char* hint = ""; #endif - mi_show_error_message("%s: at block %p of size %zu allocated at 0x%p.\n%s", msg, block, size, return_addr, hint); + mi_show_error_message("%s: block %p of size %zu allocated at 0x%p.\n%s", msg, block, size, return_addr, hint); } else if (fname != NULL) { - mi_show_error_message("%s: at block %p of size %zu allocated at %s:%i.\n", msg, block, size, fname, lineno); + mi_show_error_message("%s: block %p of size %zu allocated at %s:%i.\n", msg, block, size, fname, lineno); } else { - mi_show_error_message("%s: at block %p of size %zu.\n", msg, block, mi_page_usable_block_size(page)); + mi_show_error_message("%s: block %p of size %zu.\n", msg, block, mi_page_usable_block_size(page)); } #else - mi_show_error_message("%s: at block %p of size %zu.\n", msg, block, mi_page_usable_block_size(page)); + mi_show_error_message("%s: block %p of size %zu.\n", msg, block, mi_page_usable_block_size(page)); #endif mi_call_error_handler(err); } diff --git a/test/main-override-static.c b/test/main-override-static.c index ecf61468..2082c024 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -11,6 +11,7 @@ static void double_free1(); static void double_free2(); static void corrupt_free(); static void block_overflow1(); +static void block_overflow2(); static void dangling_ptr_write(); int main() { @@ -20,7 +21,8 @@ int main() { // double_free1(); // double_free2(); // corrupt_free(); - block_overflow1(); + // block_overflow1(); + block_overflow2(); // dangling_ptr_write(); void* p1 = malloc(78); @@ -51,6 +53,21 @@ static void block_overflow1() { free(p); } +static void block_overflow2() { + void* p[100]; + for (int i = 0; i < 100; i++) { + p[i] = mi_malloc(17); + } + memset(p[10], 0, 90); + memset(p[40], 0, 90); + memset(p[79], 0, 70); + for (int i = 99; i >= 0; i-=2) { + if (i > 0) free(p[i - 1]); + free(p[i]); + } +} + + static void dangling_ptr_write() { for (int i = 0; i < 1000; i++) { uint8_t* p = (uint8_t*)mi_malloc(16);