From 6536e51a32c81ef916a6df747c1a1e97941daef8 Mon Sep 17 00:00:00 2001 From: Guillaume Souchere Date: Thu, 25 Aug 2022 13:12:53 +0200 Subject: [PATCH] heap: Provide tlsf_check_hook() mechanism to check for memory corruption Add a call to tlsf_check_hook() in tlsf_check() that calls multi_heap_internal_check_block_poisoning() and check the memory of every free blocks when heap poisoning is active. --- components/heap/heap_tlsf.c | 26 ++++++++++++++++++++++++-- components/heap/multi_heap.c | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/components/heap/heap_tlsf.c b/components/heap/heap_tlsf.c index e5f826011f..8251796339 100644 --- a/components/heap/heap_tlsf.c +++ b/components/heap/heap_tlsf.c @@ -493,7 +493,7 @@ typedef struct integrity_t int status; } integrity_t; -#define tlsf_insist(x) { tlsf_assert(x); if (!(x)) { status--; } } +#define tlsf_insist(x) { if (!(x)) { status--; } } static void integrity_walker(void* ptr, size_t size, int used, void* user) { @@ -512,6 +512,10 @@ static void integrity_walker(void* ptr, size_t size, int used, void* user) integ->status += status; } +#ifdef MULTI_HEAP_POISONING +extern bool tlsf_check_hook(void *start, size_t size, bool is_free); +#endif + int tlsf_check(tlsf_t tlsf) { int i, j; @@ -548,7 +552,8 @@ int tlsf_check(tlsf_t tlsf) while (block != &control->block_null) { int fli, sli; - tlsf_insist(block_is_free(block) && "block should be free"); + const bool is_block_free = block_is_free(block); + tlsf_insist(is_block_free && "block should be free"); tlsf_insist(!block_is_prev_free(block) && "blocks should have coalesced"); tlsf_insist(!block_is_free(block_next(block)) && "blocks should have coalesced"); tlsf_insist(block_is_prev_free(block_next(block)) && "block should be free"); @@ -556,6 +561,23 @@ int tlsf_check(tlsf_t tlsf) mapping_insert(block_size(block), &fli, &sli); tlsf_insist(fli == i && sli == j && "block size indexed in wrong list"); + +#ifdef MULTI_HEAP_POISONING + /* block_size(block) returns the size of the usable memory when the block is allocated. + * As the block under test is free, we need to subtract to the block size the next_free + * and prev_free fields of the block header as they are not a part of the usable memory + * when the block is free. In addition, we also need to subtract the size of prev_phys_block + * as this field is in fact part of the current free block and not part of the next (allocated) + * block. Check the comments in block_split function for more details. + */ + const size_t actual_free_block_size = block_size(block) + - offsetof(block_header_t, next_free) + - block_header_overhead; + + tlsf_insist(tlsf_check_hook((void*)block + sizeof(block_header_t), + actual_free_block_size, is_block_free)); +#endif + block = block->next_free; } } diff --git a/components/heap/multi_heap.c b/components/heap/multi_heap.c index 43790389b7..01775d98a7 100644 --- a/components/heap/multi_heap.c +++ b/components/heap/multi_heap.c @@ -290,13 +290,47 @@ void *multi_heap_aligned_alloc_impl(multi_heap_handle_t heap, size_t size, size_ return multi_heap_aligned_alloc_impl_offs(heap, size, alignment, 0); } + +#ifdef MULTI_HEAP_POISONING +/*! + * @brief Global definition of print_errors set in multi_heap_check() when + * MULTI_HEAP_POISONING is active. Allows the transfer of the value to + * multi_heap_poisoning.c without having to propagate it to the tlsf submodule + * and back. + */ +static bool g_print_errors = false; + +/*! + * @brief Definition of the weak function declared in TLSF repository. + * The call of this function execute a check for block poisoning on the memory + * chunk passed as parameter. + * + * @param start: pointer to the start of the memory region to check for corruption + * @param size: size of the memory region to check for corruption + * @param is_free: indicate if the pattern to use the fill the region should be + * an after free or after allocation pattern. + * + * @return bool: true if the the memory is not corrupted, false if the memory if corrupted. + */ +bool tlsf_check_hook(void *start, size_t size, bool is_free) +{ + return multi_heap_internal_check_block_poisoning(start, size, is_free, g_print_errors); +} +#endif // MULTI_HEAP_POISONING + bool multi_heap_check(multi_heap_handle_t heap, bool print_errors) { - (void)print_errors; bool valid = true; assert(heap != NULL); multi_heap_internal_lock(heap); + + #ifdef MULTI_HEAP_POISONING + g_print_errors = print_errors; + #else + (void) print_errors; + #endif + if(tlsf_check(heap->heap_data)) { valid = false; }