From: Andrey Konovalov <andreyknvl@xxxxxxxxxx> kasan_record_aux_stack can be called concurrently on the same object. This might lead to a race condition when rotating the saved aux stack trace handles. Fix by introducing a spinlock to protect the aux stack trace handles in kasan_record_aux_stack. Reported-by: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx> Reported-by: syzbot+186b55175d8360728234@xxxxxxxxxxxxxxxxxxxxxxxxx Closes: https://lore.kernel.org/all/000000000000784b1c060b0074a2@xxxxxxxxxx/ Signed-off-by: Andrey Konovalov <andreyknvl@xxxxxxxxxx> --- This can be squashed into "kasan: use stack_depot_put for Generic mode" or left standalone. --- mm/kasan/generic.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 54e20b2bc3e1..ca5c75a1866c 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -25,6 +25,7 @@ #include <linux/sched.h> #include <linux/sched/task_stack.h> #include <linux/slab.h> +#include <linux/spinlock.h> #include <linux/stackdepot.h> #include <linux/stacktrace.h> #include <linux/string.h> @@ -35,6 +36,8 @@ #include "kasan.h" #include "../slab.h" +DEFINE_SPINLOCK(aux_lock); + /* * All functions below always inlined so compiler could * perform better optimizations in each of __asan_loadX/__assn_storeX @@ -502,6 +505,8 @@ static void __kasan_record_aux_stack(void *addr, depot_flags_t depot_flags) struct kmem_cache *cache; struct kasan_alloc_meta *alloc_meta; void *object; + depot_stack_handle_t new_handle, old_handle; + unsigned long flags; if (is_kfence_address(addr) || !slab) return; @@ -512,9 +517,15 @@ static void __kasan_record_aux_stack(void *addr, depot_flags_t depot_flags) if (!alloc_meta) return; - stack_depot_put(alloc_meta->aux_stack[1]); + new_handle = kasan_save_stack(0, depot_flags); + + spin_lock_irqsave(&aux_lock, flags); + old_handle = alloc_meta->aux_stack[1]; alloc_meta->aux_stack[1] = alloc_meta->aux_stack[0]; - alloc_meta->aux_stack[0] = kasan_save_stack(0, depot_flags); + alloc_meta->aux_stack[0] = new_handle; + spin_unlock_irqrestore(&aux_lock, flags); + + stack_depot_put(old_handle); } void kasan_record_aux_stack(void *addr) -- 2.25.1