Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86: Snapshot thread flags

Some thread flags can be set remotely, and so even when IRQs are disabled,
the flags can change under our feet. Generally this is unlikely to cause a
problem in practice, but it is somewhat unsound, and KCSAN will
legitimately warn that there is a data race.

To avoid such issues, a snapshot of the flags has to be taken prior to
using them. Some places already use READ_ONCE() for that, others do not.

Convert them all to the new flag accessor helpers.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Paul E. McKenney <paulmck@kernel.org>
Link: https://lore.kernel.org/r/20211129130653.2037928-12-mark.rutland@arm.com

authored by

Mark Rutland and committed by
Thomas Gleixner
dca99fb6 7ad63984

+7 -7
+4 -4
arch/x86/kernel/process.c
··· 365 365 clear_thread_flag(TIF_SSBD); 366 366 task_clear_spec_ssb_disable(current); 367 367 task_clear_spec_ssb_noexec(current); 368 - speculation_ctrl_update(task_thread_info(current)->flags); 368 + speculation_ctrl_update(read_thread_flags()); 369 369 } 370 370 } 371 371 ··· 617 617 clear_tsk_thread_flag(tsk, TIF_SPEC_IB); 618 618 } 619 619 /* Return the updated threadinfo flags*/ 620 - return task_thread_info(tsk)->flags; 620 + return read_task_thread_flags(tsk); 621 621 } 622 622 623 623 void speculation_ctrl_update(unsigned long tif) ··· 653 653 { 654 654 unsigned long tifp, tifn; 655 655 656 - tifn = READ_ONCE(task_thread_info(next_p)->flags); 657 - tifp = READ_ONCE(task_thread_info(prev_p)->flags); 656 + tifn = read_task_thread_flags(next_p); 657 + tifp = read_task_thread_flags(prev_p); 658 658 659 659 switch_to_bitmap(tifp); 660 660
+2 -2
arch/x86/kernel/process.h
··· 13 13 static inline void switch_to_extra(struct task_struct *prev, 14 14 struct task_struct *next) 15 15 { 16 - unsigned long next_tif = task_thread_info(next)->flags; 17 - unsigned long prev_tif = task_thread_info(prev)->flags; 16 + unsigned long next_tif = read_task_thread_flags(next); 17 + unsigned long prev_tif = read_task_thread_flags(prev); 18 18 19 19 if (IS_ENABLED(CONFIG_SMP)) { 20 20 /*
+1 -1
arch/x86/mm/tlb.c
··· 361 361 362 362 static unsigned long mm_mangle_tif_spec_bits(struct task_struct *next) 363 363 { 364 - unsigned long next_tif = task_thread_info(next)->flags; 364 + unsigned long next_tif = read_task_thread_flags(next); 365 365 unsigned long spec_bits = (next_tif >> TIF_SPEC_IB) & LAST_USER_MM_SPEC_MASK; 366 366 367 367 /*