From: "Paul E. McKenney" paulmck@kernel.org
mainline inclusion from mainline-v5.6-rc1 commit 844a378de3372c923909681706d62336d702531e category: bugfix bugzilla: 28851 CVE: NA
-------------------------------------------------------------------------
The ->srcu_last_gp_end field is accessed from any CPU at any time by synchronize_srcu(), so non-initialization references need to use READ_ONCE() and WRITE_ONCE(). This commit therefore makes that change.
Reported-by: syzbot+08f3e9d26e5541e1ecf2@syzkaller.appspotmail.com Acked-by: Marco Elver elver@google.com Signed-off-by: Paul E. McKenney paulmck@kernel.org Conflicts: kernel/rcu/srcutree.c
Signed-off-by: Zhen Lei thunder.leizhen@huawei.com Reviewed-by: Xie XiuQi xiexiuqi@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- kernel/rcu/srcutree.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c index 4b0a6e319b2cd..7bd02047b63ef 100644 --- a/kernel/rcu/srcutree.c +++ b/kernel/rcu/srcutree.c @@ -552,7 +552,7 @@ static void srcu_gp_end(struct srcu_struct *sp) idx = rcu_seq_state(sp->srcu_gp_seq); WARN_ON_ONCE(idx != SRCU_STATE_SCAN2); cbdelay = srcu_get_delay(sp); - sp->srcu_last_gp_end = ktime_get_mono_fast_ns(); + WRITE_ONCE(sp->srcu_last_gp_end, ktime_get_mono_fast_ns()); rcu_seq_end(&sp->srcu_gp_seq); gpseq = rcu_seq_current(&sp->srcu_gp_seq); if (ULONG_CMP_LT(sp->srcu_gp_seq_needed_exp, gpseq)) @@ -780,6 +780,7 @@ static bool srcu_might_be_idle(struct srcu_struct *sp) unsigned long flags; struct srcu_data *sdp; unsigned long t; + unsigned long tlast;
/* If the local srcu_data structure has callbacks, not idle. */ local_irq_save(flags); @@ -798,9 +799,9 @@ static bool srcu_might_be_idle(struct srcu_struct *sp)
/* First, see if enough time has passed since the last GP. */ t = ktime_get_mono_fast_ns(); + tlast = READ_ONCE(sp->srcu_last_gp_end); if (exp_holdoff == 0 || - time_in_range_open(t, sp->srcu_last_gp_end, - sp->srcu_last_gp_end + exp_holdoff)) + time_in_range_open(t, tlast, tlast + exp_holdoff)) return false; /* Too soon after last GP. */
/* Next, check for probable idleness. */