From: Caleb Kan KMSAN stores ordinary origin stacks and synthetic alloca and chain origins as persistent stack depot records. Once trie storage is enabled, these handles can be trie-backed, while kmsan_print_origin() still relies on the hash-only stack_depot_fetch() API. Use one KMSAN_STACK_DEPTH array to materialize each origin and chained stack in turn. Preserve the chain's head and next-origin handles before reusing the array for the chained stack. The array covers both the regular save limit and the smaller synthetic records. lib/stackdepot.c is uninstrumented, so stack_depot_fetch_into() unpoisons the successfully copied range before returning it to KMSAN. Remove the now-redundant explicit unpoisoning of chained entries. Origin depth and use-after-free metadata remain in the handle's extra bits and are unchanged. Update test_stackdepot_roundtrip() to use caller-owned storage while retaining its frame-count and kmsan_check_memory() checks. This verifies that the copy-out API returns initialized entries to instrumented callers. Signed-off-by: Caleb Kan --- mm/kmsan/kmsan_test.c | 4 ++-- mm/kmsan/report.c | 17 +++++++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/mm/kmsan/kmsan_test.c b/mm/kmsan/kmsan_test.c index 31f47cc4dab4..7c04e4b21873 100644 --- a/mm/kmsan/kmsan_test.c +++ b/mm/kmsan/kmsan_test.c @@ -669,7 +669,7 @@ static void test_long_origin_chain(struct kunit *test) */ static void test_stackdepot_roundtrip(struct kunit *test) { - unsigned long src_entries[16], *dst_entries; + unsigned long src_entries[16], dst_entries[16]; unsigned int src_nentries, dst_nentries; EXPECTATION_NO_REPORT(expect); depot_stack_handle_t handle; @@ -680,7 +680,7 @@ static void test_stackdepot_roundtrip(struct kunit *test) stack_trace_save(src_entries, ARRAY_SIZE(src_entries), 1); handle = stack_depot_save(src_entries, src_nentries, GFP_KERNEL); stack_depot_print(handle); - dst_nentries = stack_depot_fetch(handle, &dst_entries); + dst_nentries = stack_depot_fetch_into(handle, dst_entries, ARRAY_SIZE(dst_entries)); KUNIT_EXPECT_TRUE(test, src_nentries == dst_nentries); kmsan_check_memory((void *)dst_entries, diff --git a/mm/kmsan/report.c b/mm/kmsan/report.c index d6853ce08954..c20c24cffde5 100644 --- a/mm/kmsan/report.c +++ b/mm/kmsan/report.c @@ -85,7 +85,7 @@ static char *pretty_descr(char *descr) void kmsan_print_origin(depot_stack_handle_t origin) { - unsigned long *entries = NULL, *chained_entries = NULL; + unsigned long entries[KMSAN_STACK_DEPTH]; unsigned int nr_entries, chained_nr_entries, skipnr; void *pc1 = NULL, *pc2 = NULL; depot_stack_handle_t head; @@ -97,7 +97,8 @@ void kmsan_print_origin(depot_stack_handle_t origin) return; while (true) { - nr_entries = stack_depot_fetch(origin, &entries); + nr_entries = + stack_depot_fetch_into(origin, entries, ARRAY_SIZE(entries)); depth = kmsan_depth_from_eb(stack_depot_get_extra_bits(origin)); magic = nr_entries ? entries[0] : 0; if ((nr_entries == 4) && (magic == KMSAN_ALLOCA_MAGIC_ORIGIN)) { @@ -123,14 +124,10 @@ void kmsan_print_origin(depot_stack_handle_t origin) origin = entries[2]; pr_err("Uninit was stored to memory at:\n"); chained_nr_entries = - stack_depot_fetch(head, &chained_entries); - kmsan_internal_unpoison_memory( - chained_entries, - chained_nr_entries * sizeof(*chained_entries), - /*checked*/ false); - skipnr = get_stack_skipnr(chained_entries, - chained_nr_entries); - stack_trace_print(chained_entries + skipnr, + stack_depot_fetch_into(head, entries, + ARRAY_SIZE(entries)); + skipnr = get_stack_skipnr(entries, chained_nr_entries); + stack_trace_print(entries + skipnr, chained_nr_entries - skipnr, 0); pr_err("\n"); continue; -- Git-155)