diff options
Diffstat (limited to 'patches/timers__Move_clearing_of_base__timer_running_under_base__lock.patch')
-rw-r--r-- | patches/timers__Move_clearing_of_base__timer_running_under_base__lock.patch | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/patches/timers__Move_clearing_of_base__timer_running_under_base__lock.patch b/patches/timers__Move_clearing_of_base__timer_running_under_base__lock.patch new file mode 100644 index 000000000000..dd75811f2c9e --- /dev/null +++ b/patches/timers__Move_clearing_of_base__timer_running_under_base__lock.patch @@ -0,0 +1,62 @@ +Subject: timers: Move clearing of base::timer_running under base::lock +From: Thomas Gleixner <tglx@linutronix.de> +Date: Sun Dec 6 22:40:07 2020 +0100 + +From: Thomas Gleixner <tglx@linutronix.de> + +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 for a +non-RT kernel it's 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 and definitely not worth the +trouble of adding boatloads of comments and annotations to the code. Famous +last words... + +Reported-by: syzbot+aa7c2385d46c5eba0b89@syzkaller.appspotmail.com +Reported-by: syzbot+abea4558531bae1ba9fe@syzkaller.appspotmail.com +Link: https://lkml.kernel.org/r/87lfea7gw8.fsf@nanos.tec.linutronix.de +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Cc: stable-rt@vger.kernel.org + + +--- + kernel/time/timer.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) +--- +diff --git a/kernel/time/timer.c b/kernel/time/timer.c +index d111adf4a0cb..9b73908a4c53 100644 +--- a/kernel/time/timer.c ++++ b/kernel/time/timer.c +@@ -1277,8 +1277,10 @@ static inline void timer_base_unlock_expiry(struct timer_base *base) + static void timer_sync_wait_running(struct timer_base *base) + { + if (atomic_read(&base->timer_waiters)) { ++ raw_spin_unlock_irq(&base->lock); + spin_unlock(&base->expiry_lock); + spin_lock(&base->expiry_lock); ++ raw_spin_lock_irq(&base->lock); + } + } + +@@ -1469,14 +1471,14 @@ static void expire_timers(struct timer_base *base, struct hlist_head *head) + if (timer->flags & TIMER_IRQSAFE) { + raw_spin_unlock(&base->lock); + call_timer_fn(timer, fn, baseclk); +- base->running_timer = NULL; + raw_spin_lock(&base->lock); ++ base->running_timer = NULL; + } else { + raw_spin_unlock_irq(&base->lock); + call_timer_fn(timer, fn, baseclk); ++ raw_spin_lock_irq(&base->lock); + base->running_timer = NULL; + timer_sync_wait_running(base); +- raw_spin_lock_irq(&base->lock); + } + } + } |