rcu: Provide optional RCU-reader exit delay for strict GPs
authorPaul E. McKenney <paulmck@kernel.org>
Fri, 7 Aug 2020 20:44:10 +0000 (13:44 -0700)
committerPaul E. McKenney <paulmck@kernel.org>
Tue, 25 Aug 2020 01:40:27 +0000 (18:40 -0700)
The goal of this series is to increase the probability of tools like
KASAN detecting that an RCU-protected pointer was used outside of its
RCU read-side critical section.  Thus far, the approach has been to make
grace periods and callback processing happen faster.  Another approach
is to delay the pointer leaker.  This commit therefore allows a delay
to be applied to exit from RCU read-side critical sections.

This slowdown is specified by a new rcutree.rcu_unlock_delay kernel boot
parameter that specifies this delay in microseconds, defaulting to zero.

Reported-by Jann Horn <jannh@google.com>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
Documentation/admin-guide/kernel-parameters.txt
kernel/rcu/tree_plugin.h

index bdc1f33..cb90624 100644 (file)
                        This wake_up() will be accompanied by a
                        WARN_ONCE() splat and an ftrace_dump().
 
+       rcutree.rcu_unlock_delay= [KNL]
+                       In CONFIG_RCU_STRICT_GRACE_PERIOD=y kernels,
+                       this specifies an rcu_read_unlock()-time delay
+                       in microseconds.  This defaults to zero.
+                       Larger delays increase the probability of
+                       catching RCU pointer leaks, that is, buggy use
+                       of RCU-protected pointers after the relevant
+                       rcu_read_unlock() has completed.
+
        rcutree.sysrq_rcu= [KNL]
                        Commandeer a sysrq key to dump out Tree RCU's
                        rcu_node tree with an eye towards determining
index dfdb902..3f3a4ff 100644 (file)
@@ -430,6 +430,12 @@ static bool rcu_preempt_has_tasks(struct rcu_node *rnp)
        return !list_empty(&rnp->blkd_tasks);
 }
 
+// Add delay to rcu_read_unlock() for strict grace periods.
+static int rcu_unlock_delay;
+#ifdef CONFIG_RCU_STRICT_GRACE_PERIOD
+module_param(rcu_unlock_delay, int, 0444);
+#endif
+
 /*
  * Report deferred quiescent states.  The deferral time can
  * be quite short, for example, in the case of the call from
@@ -460,10 +466,12 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags)
        }
        t->rcu_read_unlock_special.s = 0;
        if (special.b.need_qs) {
-               if (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD))
+               if (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD)) {
                        rcu_report_qs_rdp(rdp->cpu, rdp);
-               else
+                       udelay(rcu_unlock_delay);
+               } else {
                        rcu_qs();
+               }
        }
 
        /*