The actual allocated buffer size can be bigger than what was requested due to alignment.
When KASAN is enabled, only the requested size is unpoisoned. This currently leads to problems, because with CONFIG_INIT_ON_ALLOC_DEFAULT_ON enabled, the whole allocated buffer will be zeroed. If we fix that, we will instead run into a problem when freeing the buffer while CONFIG_INIT_ON_ALLOC_DEFAULT_ON is enabled: We don't record the actual size for later use and thus trying to zero all of the buffer will again trip over the poisoned padding at the end. Fix this by first unpoisoning the whole buffer, zeroing it and then restoring poisoning of off-limits memory. Signed-off-by: Ahmad Fatoum <a.fat...@pengutronix.de> --- common/tlsf.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/common/tlsf.c b/common/tlsf.c index 5504453a9453..01293630dd7c 100644 --- a/common/tlsf.c +++ b/common/tlsf.c @@ -607,10 +607,19 @@ static void* block_prepare_used(control_t* control, block_header_t* block, kasan_poison_shadow(&block->size, size + 2 * sizeof(size_t), KASAN_KMALLOC_REDZONE); - kasan_unpoison_shadow(p, used); - if (want_init_on_alloc()) + if (want_init_on_alloc()) { + kasan_unpoison_shadow(p, size); memzero_explicit(p, size); + /* + * KASAN doesn't play nicely with poisoning addresses + * that are not granule-aligned, which is why we poison + * the full size and then unpoison the rest. + */ + kasan_poison_shadow(p, size, 0xff); + } + + kasan_unpoison_shadow(p, used); } return p; } @@ -1017,8 +1026,10 @@ void tlsf_free(tlsf_t tlsf, void* ptr) control_t* control = tlsf_cast(control_t*, tlsf); block_header_t* block = block_from_ptr(ptr); tlsf_assert(!block_is_free(block) && "block already marked as free"); - if (want_init_on_free()) + if (want_init_on_free()) { + kasan_unpoison_shadow(ptr, block_size(block)); memzero_explicit(ptr, block_size(block)); + } kasan_poison_shadow(ptr, block_size(block), 0xff); block_mark_as_free(block); block = block_merge_prev(control, block); -- 2.39.5