Skip to content

Commit 747c0f3

Browse files
melverakpm00
authored andcommitted
kfence: fix stack trace pruning
Commit b140513 ("mm/sl[au]b: generalize kmalloc subsystem") refactored large parts of the kmalloc subsystem, resulting in the stack trace pruning logic done by KFENCE to no longer work. While b140513 attempted to fix the situation by including '__kmem_cache_free' in the list of functions KFENCE should skip through, this only works when the compiler actually optimized the tail call from kfree() to __kmem_cache_free() into a jump (and thus kfree() _not_ appearing in the full stack trace to begin with). In some configurations, the compiler no longer optimizes the tail call into a jump, and __kmem_cache_free() appears in the stack trace. This means that the pruned stack trace shown by KFENCE would include kfree() which is not intended - for example: | BUG: KFENCE: invalid free in kfree+0x7c/0x120 | | Invalid free of 0xffff8883ed8fefe0 (in kfence-torvalds#126): | kfree+0x7c/0x120 | test_double_free+0x116/0x1a9 | kunit_try_run_case+0x90/0xd0 | [...] Fix it by moving __kmem_cache_free() to the list of functions that may be tail called by an allocator entry function, making the pruning logic work in both the optimized and unoptimized tail call cases. Link: https://lkml.kernel.org/r/20221118152216.3914899-1-elver@google.com Fixes: b140513 ("mm/sl[au]b: generalize kmalloc subsystem") Signed-off-by: Marco Elver <elver@google.com> Reviewed-by: Alexander Potapenko <glider@google.com> Cc: Hyeonggon Yoo <42.hyeyoo@gmail.com> Cc: Feng Tang <feng.tang@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent f850c84 commit 747c0f3

File tree

1 file changed

+9
-4
lines changed

1 file changed

+9
-4
lines changed

mm/kfence/report.c

+9-4
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,23 @@ static int get_stack_skipnr(const unsigned long stack_entries[], int num_entries
7575

7676
if (str_has_prefix(buf, ARCH_FUNC_PREFIX "kfence_") ||
7777
str_has_prefix(buf, ARCH_FUNC_PREFIX "__kfence_") ||
78+
str_has_prefix(buf, ARCH_FUNC_PREFIX "__kmem_cache_free") ||
7879
!strncmp(buf, ARCH_FUNC_PREFIX "__slab_free", len)) {
7980
/*
80-
* In case of tail calls from any of the below
81-
* to any of the above.
81+
* In case of tail calls from any of the below to any of
82+
* the above, optimized by the compiler such that the
83+
* stack trace would omit the initial entry point below.
8284
*/
8385
fallback = skipnr + 1;
8486
}
8587

86-
/* Also the *_bulk() variants by only checking prefixes. */
88+
/*
89+
* The below list should only include the initial entry points
90+
* into the slab allocators. Includes the *_bulk() variants by
91+
* checking prefixes.
92+
*/
8793
if (str_has_prefix(buf, ARCH_FUNC_PREFIX "kfree") ||
8894
str_has_prefix(buf, ARCH_FUNC_PREFIX "kmem_cache_free") ||
89-
str_has_prefix(buf, ARCH_FUNC_PREFIX "__kmem_cache_free") ||
9095
str_has_prefix(buf, ARCH_FUNC_PREFIX "__kmalloc") ||
9196
str_has_prefix(buf, ARCH_FUNC_PREFIX "kmem_cache_alloc"))
9297
goto found;

0 commit comments

Comments
 (0)