diff --git a/arch/x86/include/asm/page_64.h b/arch/x86/include/asm/page_64.h index cc6b8e087192..f13bba3a9dab 100644 --- a/arch/x86/include/asm/page_64.h +++ b/arch/x86/include/asm/page_64.h @@ -58,7 +58,16 @@ static inline void clear_page(void *page) : "cc", "memory", "rax", "rcx"); } +#ifdef CONFIG_KMSAN +/* Use of non-instrumented assembly version confuses KMSAN. */ +void *memcpy(void *to, const void *from, __kernel_size_t len); +static inline void copy_page(void *to, void *from) +{ + memcpy(to, from, PAGE_SIZE); +} +#else void copy_page(void *to, void *from); +#endif #ifdef CONFIG_X86_5LEVEL /* diff --git a/lib/stackdepot.c b/lib/stackdepot.c index 5caa1f566553..48277029c282 100644 --- a/lib/stackdepot.c +++ b/lib/stackdepot.c @@ -592,22 +592,27 @@ static inline struct stack_record *find_stack(struct list_head *bucket, /* * This may race with depot_free_stack() accessing the freelist - * management state unioned with @entries. The refcount is zero - * in that case and the below refcount_inc_not_zero() will fail. + * management state unioned with @entries. */ if (data_race(stackdepot_memcmp(entries, stack->entries, size))) continue; /* - * Try to increment refcount. If this succeeds, the stack record - * is valid and has not yet been freed. + * Check if an invalid record had the same {hash, size, entries} + * by testing whether the refcount is already 0. + * Also, try to increment refcount if STACK_DEPOT_FLAG_GET is used. * * If STACK_DEPOT_FLAG_GET is not used, it is undefined behavior * to then call stack_depot_put() later, and we can assume that * a stack record is never placed back on the freelist. */ - if ((flags & STACK_DEPOT_FLAG_GET) && !refcount_inc_not_zero(&stack->count)) - continue; + if (flags & STACK_DEPOT_FLAG_GET) { + if (!refcount_inc_not_zero(&stack->count)) + continue; + } else { + if (!refcount_read(&stack->count)) + continue; + } ret = stack; break;