add corrupted block scanning on overflow detection

This commit is contained in:
daan 2020-04-06 16:10:43 -07:00
parent 083392fa15
commit 8a7d5804bc
3 changed files with 67 additions and 14 deletions

View File

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

View File

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

View File

@ -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);