diff options
Diffstat (limited to 'features/rt/timers-Move-clearing-of-base-timer_running-under-bas.patch')
-rw-r--r-- | features/rt/timers-Move-clearing-of-base-timer_running-under-bas.patch | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/features/rt/timers-Move-clearing-of-base-timer_running-under-bas.patch b/features/rt/timers-Move-clearing-of-base-timer_running-under-bas.patch new file mode 100644 index 00000000..c95178d3 --- /dev/null +++ b/features/rt/timers-Move-clearing-of-base-timer_running-under-bas.patch @@ -0,0 +1,62 @@ +From 13ae7118b5e43a9fd44640f31eb1df12f580a13e Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner <tglx@linutronix.de> +Date: Sun, 6 Dec 2020 22:40:07 +0100 +Subject: [PATCH 002/191] timers: Move clearing of base::timer_running under + base::lock + +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> +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 f475f1a027c8..a0ec4450b1d8 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); + } + } + } +-- +2.19.1 + |