On Thu, Aug 20, 2020 at 10:36AM -0400, Steven Rostedt wrote: > > I tested this series on top of tip/master and triggered the below > warning when running the irqsoff tracer boot up test (config attached). > > -- Steve > > Testing tracer irqsoff: > > ============================= > WARNING: suspicious RCU usage > 5.9.0-rc1-test+ #92 Not tainted > ----------------------------- > include/trace/events/lock.h:13 suspicious rcu_dereference_check() usage! > > other info that might help us debug this: > > > rcu_scheduler_active = 2, debug_locks = 1 > RCU used illegally from extended quiescent state! > no locks held by swapper/2/0. > > stack backtrace: > CPU: 2 PID: 0 Comm: swapper/2 Not tainted 5.9.0-rc1-test+ #92 > Hardware name: Hewlett-Packard HP Compaq Pro 6300 SFF/339A, BIOS K01 v03.03 07/14/2016 > Call Trace: > dump_stack+0x8d/0xc0 > lock_acquire.cold+0x23/0x2c > ? default_idle_call+0x4d/0x210 > _raw_spin_lock_irqsave+0x50/0xa0 > ? check_critical_timing+0x69/0x160 > check_critical_timing+0x69/0x160 > ? default_idle_call+0x4d/0x210 > stop_critical_timings+0xdd/0xf0 > default_idle_call+0x4d/0x210 > do_idle+0x1f6/0x260 > cpu_startup_entry+0x19/0x20 > start_secondary+0x110/0x140 > secondary_startup_64+0xb6/0xc0 Ah, I was just trying to figure out if it's due to KCSAN instrumentation or not. I ran into a similar warning due to tracing of prandom_u32(), that also triggered lockdep warnings (all warnings attached). Otherwise, this survived syzkaller testing until I enabled KCSAN. :-/ The first thing KCSAN wants is to just guard against recursion due to tracing even if KCSAN instrumentation is disabled for the function. This recursion seems to be new. I got further with the below patch for KCSAN. Unfortunately there are a bunch of merge conflicts with latest KCSAN on -rcu tree if you were to attach the patch to your series, so not sure what the best strategy here is. Config is also attached. Thanks, -- Marco ------ >8 ------ From 5b12649cbcf0c7d164e6995c40ce88a4e3e86f28 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Thu, 6 Aug 2020 14:19:10 +0200 Subject: [PATCH] kcsan: Avoid recursion due to tracing We can observe recursion due to calling library functions that are being traced from kcsan_setup_watchpoint(). This can happen even though instrumentation is disabled for such functions. For example in lib/random32.o (where instrumentation is disabled), we may still get recursion with recent changes to tracing: prandom_u32+0x11/0xe0 kcsan_setup_watchpoint+0x32/0x580 rcu_is_watching+0x21/0x60 rcu_read_lock_sched_held+0x26/0xa0 trace_prandom_u32+0x7e/0x190 prandom_u32+0xa8/0xe0 kcsan_setup_watchpoint+0x32/0x580 rcu_is_watching+0x21/0x60 rcu_read_lock_sched_held+0x26/0xa0 trace_prandom_u32+0x7e/0x190 prandom_u32+0xa8/0xe0 kcsan_setup_watchpoint+0x32/0x580 ... Avoid the recursion by disabling KCSAN in the following regions in kcsan_setup_watchpoint(): - after checking if KCSAN is enabled, to before delay initiation; - after the delay, until the end of the function. The exception that remains is udelay(), where we want to keep KCSAN enabled as otherwise we would miss races between nested interrupts. Signed-off-by: Marco Elver --- kernel/kcsan/core.c | 52 +++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/kernel/kcsan/core.c b/kernel/kcsan/core.c index 9147ff6a12e5..c5a295afdb94 100644 --- a/kernel/kcsan/core.c +++ b/kernel/kcsan/core.c @@ -261,14 +261,15 @@ should_watch(const volatile void *ptr, size_t size, int type, struct kcsan_ctx * return false; /* - * NOTE: If we get here, kcsan_skip must always be reset in slow path - * via reset_kcsan_skip() to avoid underflow. + * Note: If we get here, kcsan_skip must always be reset in slow path to + * avoid underflow. */ /* this operation should be watched */ return true; } +/* Requires: KCSAN is disabled, to avoid prandom_u32() recursion. */ static inline void reset_kcsan_skip(void) { long skip_count = kcsan_skip_watch - @@ -283,12 +284,23 @@ static __always_inline bool kcsan_is_enabled(void) return READ_ONCE(kcsan_enabled) && get_ctx()->disable_count == 0; } -static inline unsigned int get_delay(void) +/* + * Introduce delay depending on context and configuration. + * Requires: KCSAN is disabled, to avoid prandom_u32() recursion. + */ +static void delay_access(void) { unsigned int delay = in_task() ? kcsan_udelay_task : kcsan_udelay_interrupt; - return delay - (IS_ENABLED(CONFIG_KCSAN_DELAY_RANDOMIZE) ? - prandom_u32_max(delay) : - 0); + + /* + * Call prandom_u32_max() with KCSAN disabled, as tracing may be + * enabled, which would cause recursion. + */ + delay -= IS_ENABLED(CONFIG_KCSAN_DELAY_RANDOMIZE) ? prandom_u32_max(delay) : 0; + + kcsan_enable_current(); + udelay(delay); + kcsan_disable_current(); } void kcsan_save_irqtrace(struct task_struct *task) @@ -386,17 +398,30 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type) } expect_value; unsigned long access_mask; enum kcsan_value_change value_change = KCSAN_VALUE_CHANGE_MAYBE; - unsigned long ua_flags = user_access_save(); + unsigned long ua_flags = 0; unsigned long irq_flags = 0; /* * Always reset kcsan_skip counter in slow-path to avoid underflow; see - * should_watch(). + * should_watch(). This write is redundant if KCSAN is enabled, as we + * call reset_kcsan_skip() below, yet we cannot call reset_kcsan_skip() + * here to avoid prandom_u32() recursion. */ - reset_kcsan_skip(); - + this_cpu_write(kcsan_skip, kcsan_skip_watch); if (!kcsan_is_enabled()) - goto out; + return; + + ua_flags = user_access_save(); + + /* + * Disable KCSAN to ensure that library functions we call do not result + * in recursion. This can still occur even if instrumentation is + * disabled for these functions, but tracing is enabled. + */ + kcsan_disable_current(); + + /* Randomized reset, after enabled-check to avoid recursion. */ + reset_kcsan_skip(); /* * Special atomic rules: unlikely to be true, so we check them here in @@ -458,19 +483,17 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type) } if (IS_ENABLED(CONFIG_KCSAN_DEBUG)) { - kcsan_disable_current(); pr_err("KCSAN: watching %s, size: %zu, addr: %px [slot: %d, encoded: %lx]\n", is_write ? "write" : "read", size, ptr, watchpoint_slot((unsigned long)ptr), encode_watchpoint((unsigned long)ptr, size, is_write)); - kcsan_enable_current(); } /* * Delay this thread, to increase probability of observing a racy * conflicting access. */ - udelay(get_delay()); + delay_access(); /* * Re-read value, and check if it is as expected; if not, we infer a @@ -563,6 +586,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type) local_irq_restore(irq_flags); kcsan_restore_irqtrace(current); out: + kcsan_enable_current_nowarn(); user_access_restore(ua_flags); } -- 2.28.0.297.g1956fa8f8d-goog