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.
This commit is contained in:
Guillaume Souchere 2022-08-25 13:12:53 +02:00
parent 41839b69bd
commit 6536e51a32
2 changed files with 59 additions and 3 deletions

View File

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

View File

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