Commit 7e76b75e authored by Aleksei Nikiforov's avatar Aleksei Nikiforov Committed by Andrew Morton
Browse files

mm/kmsan: fix kmsan kmalloc hook when no stack depots are allocated yet

If no stack depot is allocated yet, due to masking out __GFP_RECLAIM flags
kmsan called from kmalloc cannot allocate stack depot.  kmsan fails to
record origin and report issues.  This may result in KMSAN failing to
report issues.

Reusing flags from kmalloc without modifying them should be safe for kmsan.
For example, such chain of calls is possible:
test_uninit_kmalloc -> kmalloc -> __kmalloc_cache_noprof ->
slab_alloc_node -> slab_post_alloc_hook ->
kmsan_slab_alloc -> kmsan_internal_poison_memory.

Only when it is called in a context without flags present should
__GFP_RECLAIM flags be masked.

With this change all kmsan tests start working reliably.

Eric reported:

: Yes, KMSAN seems to be at least partially broken currently.  Besides the
: fact that the kmsan KUnit test is currently failing (which I reported at
: https://lore.kernel.org/r/20250911175145.GA1376@sol), I've confirmed that
: the poly1305 KUnit test causes a KMSAN warning with Aleksei's patch
: applied but does not cause a warning without it.  The warning did get
: reached via syzbot somehow
: (https://lore.kernel.org/r/751b3d80293a6f599bb07770afcef24f623c7da0.1761026343.git.xiaopei01@kylinos.cn/),
: so KMSAN must still work in some cases.  But it didn't work for me.

Link: https://lkml.kernel.org/r/20250930115600.709776-2-aleksei.nikiforov@linux.ibm.com
Link: https://lkml.kernel.org/r/20251022030213.GA35717@sol


Fixes: 97769a53 ("mm, bpf: Introduce try_alloc_pages() for opportunistic page allocation")
Signed-off-by: default avatarAleksei Nikiforov <aleksei.nikiforov@linux.ibm.com>
Reviewed-by: default avatarAlexander Potapenko <glider@google.com>
Tested-by: default avatarEric Biggers <ebiggers@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Dmitriy Vyukov <dvyukov@google.com>
Cc: Ilya Leoshkevich <iii@linux.ibm.com>
Cc: Marco Elver <elver@google.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent fc745ff3
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -72,9 +72,6 @@ depot_stack_handle_t kmsan_save_stack_with_flags(gfp_t flags,

	nr_entries = stack_trace_save(entries, KMSAN_STACK_DEPTH, 0);

	/* Don't sleep. */
	flags &= ~(__GFP_DIRECT_RECLAIM | __GFP_KSWAPD_RECLAIM);

	handle = stack_depot_save(entries, nr_entries, flags);
	return stack_depot_set_extra_bits(handle, extra);
}
+4 −2
Original line number Diff line number Diff line
@@ -84,7 +84,8 @@ void kmsan_slab_free(struct kmem_cache *s, void *object)
	if (s->ctor)
		return;
	kmsan_enter_runtime();
	kmsan_internal_poison_memory(object, s->object_size, GFP_KERNEL,
	kmsan_internal_poison_memory(object, s->object_size,
				     GFP_KERNEL & ~(__GFP_RECLAIM),
				     KMSAN_POISON_CHECK | KMSAN_POISON_FREE);
	kmsan_leave_runtime();
}
@@ -114,7 +115,8 @@ void kmsan_kfree_large(const void *ptr)
	kmsan_enter_runtime();
	page = virt_to_head_page((void *)ptr);
	KMSAN_WARN_ON(ptr != page_address(page));
	kmsan_internal_poison_memory((void *)ptr, page_size(page), GFP_KERNEL,
	kmsan_internal_poison_memory((void *)ptr, page_size(page),
				     GFP_KERNEL & ~(__GFP_RECLAIM),
				     KMSAN_POISON_CHECK | KMSAN_POISON_FREE);
	kmsan_leave_runtime();
}
+1 −1
Original line number Diff line number Diff line
@@ -208,7 +208,7 @@ void kmsan_free_page(struct page *page, unsigned int order)
		return;
	kmsan_enter_runtime();
	kmsan_internal_poison_memory(page_address(page), page_size(page),
				     GFP_KERNEL,
				     GFP_KERNEL & ~(__GFP_RECLAIM),
				     KMSAN_POISON_CHECK | KMSAN_POISON_FREE);
	kmsan_leave_runtime();
}