linux/kernel/time
Thomas Gleixner 23e36a8610 timers: Move clearing of base::timer_running under base:: Lock
commit bb7262b295 upstream.

syzbot reported KCSAN data races vs. timer_base::timer_running being set to
NULL without holding base::lock in expire_timers().

This looks innocent and most reads are clearly not problematic, but
Frederic identified an issue which is:

 int data = 0;

 void timer_func(struct timer_list *t)
 {
    data = 1;
 }

 CPU 0                                            CPU 1
 ------------------------------                   --------------------------
 base = lock_timer_base(timer, &flags);           raw_spin_unlock(&base->lock);
 if (base->running_timer != timer)                call_timer_fn(timer, fn, baseclk);
   ret = detach_if_pending(timer, base, true);    base->running_timer = NULL;
 raw_spin_unlock_irqrestore(&base->lock, flags);  raw_spin_lock(&base->lock);

 x = data;

If the timer has previously executed on CPU 1 and then CPU 0 can observe
base->running_timer == NULL and returns, assuming the timer has completed,
but it's not guaranteed on all architectures. The comment for
del_timer_sync() makes that guarantee. Moving the assignment under
base->lock prevents this.

For non-RT kernel it's performance wise completely irrelevant whether the
store happens before or after taking the lock. For an RT kernel moving the
store under the lock requires an extra unlock/lock pair in the case that
there is a waiter for the timer, but that's not the end of the world.

Reported-by: syzbot+aa7c2385d46c5eba0b89@syzkaller.appspotmail.com
Reported-by: syzbot+abea4558531bae1ba9fe@syzkaller.appspotmail.com
Fixes: 030dcdd197 ("timers: Prepare support for PREEMPT_RT")
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Link: https://lore.kernel.org/r/87lfea7gw8.fsf@nanos.tec.linutronix.de
Cc: stable@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-08-12 13:22:15 +02:00
..
alarmtimer.c kernel, fs: Introduce and use set_restart_fn() and arch_set_restart_data() 2021-03-25 09:04:16 +01:00
clockevents.c
clocksource.c clocksource: Check per-CPU clock synchronization when marked unstable 2021-07-14 16:56:01 +02:00
hrtimer.c kernel, fs: Introduce and use set_restart_fn() and arch_set_restart_data() 2021-03-25 09:04:16 +01:00
itimer.c time: Prevent undefined behaviour in timespec64_to_ns() 2020-10-26 11:48:11 +01:00
jiffies.c timekeeping: Split jiffies seqlock 2020-03-21 16:00:23 +01:00
Kconfig posix-cpu-timers: Provide mechanisms to defer timer handling to task_work 2020-08-06 16:50:59 +02:00
Makefile ns: Introduce Time Namespace 2020-01-14 12:20:48 +01:00
namespace.c nsproxy: support CLONE_NEWTIME with setns() 2020-07-08 11:14:22 +02:00
ntp_internal.h
ntp.c ntp/y2038: Remove incorrect time_t truncation 2019-11-12 08:13:44 +01:00
posix-clock.c posix-clocks: Rename the clock_get() callback to clock_get_timespec() 2020-01-14 12:20:49 +01:00
posix-cpu-timers.c posix-cpu-timers: Fix rearm racing against process tick 2021-07-28 14:35:45 +02:00
posix-stubs.c posix-timers: Make clock_nanosleep() time namespace aware 2020-01-14 12:20:55 +01:00
posix-timers.c posix-timers: Preserve return value in clock_adjtime32() 2021-05-11 14:47:16 +02:00
posix-timers.h posix-clocks: Introduce clock_get_ktime() callback 2020-01-14 12:20:51 +01:00
sched_clock.c time/sched_clock: Mark sched_clock_read_begin/retry() as notrace 2020-10-26 11:34:31 +01:00
test_udelay.c
tick-broadcast-hrtimer.c
tick-broadcast.c treewide: Use fallthrough pseudo-keyword 2020-08-23 17:36:59 -05:00
tick-common.c timekeeping: Split jiffies seqlock 2020-03-21 16:00:23 +01:00
tick-internal.h
tick-oneshot.c
tick-sched.c tick/sched: Remove bogus boot "safety" check 2021-01-06 14:56:55 +01:00
tick-sched.h
time.c y2038: remove unused time32 interfaces 2020-02-21 11:22:15 -08:00
timeconst.bc
timeconv.c
timecounter.c
timekeeping_debug.c
timekeeping_internal.h timekeeping/vsyscall: Provide vdso_update_begin/end() 2020-08-06 10:57:30 +02:00
timekeeping.c These are the locking updates for v5.10: 2020-10-12 13:06:20 -07:00
timekeeping.h timekeeping: Split jiffies seqlock 2020-03-21 16:00:23 +01:00
timer_list.c
timer.c timers: Move clearing of base::timer_running under base:: Lock 2021-08-12 13:22:15 +02:00
vsyscall.c timekeeping/vsyscall: Provide vdso_update_begin/end() 2020-08-06 10:57:30 +02:00