linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] kcsan: Use tracing-safe version of prandom
@ 2020-08-21 12:31 Marco Elver
  2020-08-26 12:17 ` Marco Elver
  0 siblings, 1 reply; 3+ messages in thread
From: Marco Elver @ 2020-08-21 12:31 UTC (permalink / raw)
  To: elver, paulmck; +Cc: peterz, mark.rutland, dvyukov, kasan-dev, linux-kernel

In the core runtime, we must minimize any calls to external library
functions to avoid any kind of recursion. This can happen even though
instrumentation is disabled for called functions, but tracing is
enabled.

Most recently, prandom_u32() added a tracepoint, which can cause
problems for KCSAN even if the rcuidle variant is used. For example:
	kcsan -> prandom_u32() -> trace_prandom_u32_rcuidle ->
	srcu_read_lock_notrace -> __srcu_read_lock -> kcsan ...

While we could disable KCSAN in kcsan_setup_watchpoint(), this does not
solve other unexpected behaviour we may get due recursing into functions
that may not be tolerant to such recursion:
	__srcu_read_lock -> kcsan -> ... -> __srcu_read_lock

Therefore, switch to using prandom_u32_state(), which is uninstrumented,
and does not have a tracepoint.

Link: https://lkml.kernel.org/r/20200821063043.1949509-1-elver@google.com
Link: https://lkml.kernel.org/r/20200820172046.GA177701@elver.google.com
Signed-off-by: Marco Elver <elver@google.com>
---
Applies to latest -rcu/dev only.

Let's wait a bit to see what happens with
  https://lkml.kernel.org/r/20200821063043.1949509-1-elver@google.com,
just in case there's a better solution that might make this patch redundant.
---
 kernel/kcsan/core.c | 35 +++++++++++++++++++++++++++++------
 1 file changed, 29 insertions(+), 6 deletions(-)

diff --git a/kernel/kcsan/core.c b/kernel/kcsan/core.c
index 8a1ff605ff2d..3994a217bde7 100644
--- a/kernel/kcsan/core.c
+++ b/kernel/kcsan/core.c
@@ -100,6 +100,9 @@ static atomic_long_t watchpoints[CONFIG_KCSAN_NUM_WATCHPOINTS + NUM_SLOTS-1];
  */
 static DEFINE_PER_CPU(long, kcsan_skip);
 
+/* For kcsan_prandom_u32_max(). */
+static DEFINE_PER_CPU(struct rnd_state, kcsan_rand_state);
+
 static __always_inline atomic_long_t *find_watchpoint(unsigned long addr,
 						      size_t size,
 						      bool expect_write,
@@ -271,11 +274,28 @@ should_watch(const volatile void *ptr, size_t size, int type, struct kcsan_ctx *
 	return true;
 }
 
+/*
+ * Returns a pseudo-random number in interval [0, ep_ro). See prandom_u32_max()
+ * for more details.
+ *
+ * The open-coded version here is using only safe primitives for all contexts
+ * where we can have KCSAN instrumentation. In particular, we cannot use
+ * prandom_u32() directly, as its tracepoint could cause recursion.
+ */
+static u32 kcsan_prandom_u32_max(u32 ep_ro)
+{
+	struct rnd_state *state = &get_cpu_var(kcsan_rand_state);
+	const u32 res = prandom_u32_state(state);
+
+	put_cpu_var(kcsan_rand_state);
+	return (u32)(((u64) res * ep_ro) >> 32);
+}
+
 static inline void reset_kcsan_skip(void)
 {
 	long skip_count = kcsan_skip_watch -
 			  (IS_ENABLED(CONFIG_KCSAN_SKIP_WATCH_RANDOMIZE) ?
-				   prandom_u32_max(kcsan_skip_watch) :
+				   kcsan_prandom_u32_max(kcsan_skip_watch) :
 				   0);
 	this_cpu_write(kcsan_skip, skip_count);
 }
@@ -285,16 +305,18 @@ static __always_inline bool kcsan_is_enabled(void)
 	return READ_ONCE(kcsan_enabled) && get_ctx()->disable_count == 0;
 }
 
-static inline unsigned int get_delay(int type)
+/* Introduce delay depending on context and configuration. */
+static void delay_access(int type)
 {
 	unsigned int delay = in_task() ? kcsan_udelay_task : kcsan_udelay_interrupt;
 	/* For certain access types, skew the random delay to be longer. */
 	unsigned int skew_delay_order =
 		(type & (KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_ASSERT)) ? 1 : 0;
 
-	return delay - (IS_ENABLED(CONFIG_KCSAN_DELAY_RANDOMIZE) ?
-				prandom_u32_max(delay >> skew_delay_order) :
-				0);
+	delay -= IS_ENABLED(CONFIG_KCSAN_DELAY_RANDOMIZE) ?
+			       kcsan_prandom_u32_max(delay >> skew_delay_order) :
+			       0;
+	udelay(delay);
 }
 
 void kcsan_save_irqtrace(struct task_struct *task)
@@ -476,7 +498,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
 	 * Delay this thread, to increase probability of observing a racy
 	 * conflicting access.
 	 */
-	udelay(get_delay(type));
+	delay_access(type);
 
 	/*
 	 * Re-read value, and check if it is as expected; if not, we infer a
@@ -620,6 +642,7 @@ void __init kcsan_init(void)
 	BUG_ON(!in_task());
 
 	kcsan_debugfs_init();
+	prandom_seed_full_state(&kcsan_rand_state);
 
 	/*
 	 * We are in the init task, and no other tasks should be running;
-- 
2.28.0.297.g1956fa8f8d-goog


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] kcsan: Use tracing-safe version of prandom
  2020-08-21 12:31 [PATCH] kcsan: Use tracing-safe version of prandom Marco Elver
@ 2020-08-26 12:17 ` Marco Elver
  2020-08-26 21:21   ` Paul E. McKenney
  0 siblings, 1 reply; 3+ messages in thread
From: Marco Elver @ 2020-08-26 12:17 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Peter Zijlstra, Marco Elver, Mark Rutland, Dmitry Vyukov,
	kasan-dev, LKML

On Fri, 21 Aug 2020 at 14:31, Marco Elver <elver@google.com> wrote:
> In the core runtime, we must minimize any calls to external library
> functions to avoid any kind of recursion. This can happen even though
> instrumentation is disabled for called functions, but tracing is
> enabled.
>
> Most recently, prandom_u32() added a tracepoint, which can cause
> problems for KCSAN even if the rcuidle variant is used. For example:
>         kcsan -> prandom_u32() -> trace_prandom_u32_rcuidle ->
>         srcu_read_lock_notrace -> __srcu_read_lock -> kcsan ...
>
> While we could disable KCSAN in kcsan_setup_watchpoint(), this does not
> solve other unexpected behaviour we may get due recursing into functions
> that may not be tolerant to such recursion:
>         __srcu_read_lock -> kcsan -> ... -> __srcu_read_lock
>
> Therefore, switch to using prandom_u32_state(), which is uninstrumented,
> and does not have a tracepoint.
>
> Link: https://lkml.kernel.org/r/20200821063043.1949509-1-elver@google.com
> Link: https://lkml.kernel.org/r/20200820172046.GA177701@elver.google.com
> Signed-off-by: Marco Elver <elver@google.com>
> ---
> Applies to latest -rcu/dev only.
>
> Let's wait a bit to see what happens with
>   https://lkml.kernel.org/r/20200821063043.1949509-1-elver@google.com,
> just in case there's a better solution that might make this patch redundant.

Paul, feel free to pick this up.

I wanted to wait until after plumbers to see what happens, but maybe
it's better to give the heads-up now, so this is in time for the next
pull-request. It seems that prandom_u32() will keep its tracepoint,
which means we definitely need this to make KCSAN compatible with
tracing again.

Thanks,
-- Marco

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] kcsan: Use tracing-safe version of prandom
  2020-08-26 12:17 ` Marco Elver
@ 2020-08-26 21:21   ` Paul E. McKenney
  0 siblings, 0 replies; 3+ messages in thread
From: Paul E. McKenney @ 2020-08-26 21:21 UTC (permalink / raw)
  To: Marco Elver; +Cc: Peter Zijlstra, Mark Rutland, Dmitry Vyukov, kasan-dev, LKML

On Wed, Aug 26, 2020 at 02:17:57PM +0200, Marco Elver wrote:
> On Fri, 21 Aug 2020 at 14:31, Marco Elver <elver@google.com> wrote:
> > In the core runtime, we must minimize any calls to external library
> > functions to avoid any kind of recursion. This can happen even though
> > instrumentation is disabled for called functions, but tracing is
> > enabled.
> >
> > Most recently, prandom_u32() added a tracepoint, which can cause
> > problems for KCSAN even if the rcuidle variant is used. For example:
> >         kcsan -> prandom_u32() -> trace_prandom_u32_rcuidle ->
> >         srcu_read_lock_notrace -> __srcu_read_lock -> kcsan ...
> >
> > While we could disable KCSAN in kcsan_setup_watchpoint(), this does not
> > solve other unexpected behaviour we may get due recursing into functions
> > that may not be tolerant to such recursion:
> >         __srcu_read_lock -> kcsan -> ... -> __srcu_read_lock
> >
> > Therefore, switch to using prandom_u32_state(), which is uninstrumented,
> > and does not have a tracepoint.
> >
> > Link: https://lkml.kernel.org/r/20200821063043.1949509-1-elver@google.com
> > Link: https://lkml.kernel.org/r/20200820172046.GA177701@elver.google.com
> > Signed-off-by: Marco Elver <elver@google.com>
> > ---
> > Applies to latest -rcu/dev only.
> >
> > Let's wait a bit to see what happens with
> >   https://lkml.kernel.org/r/20200821063043.1949509-1-elver@google.com,
> > just in case there's a better solution that might make this patch redundant.
> 
> Paul, feel free to pick this up.
> 
> I wanted to wait until after plumbers to see what happens, but maybe
> it's better to give the heads-up now, so this is in time for the next
> pull-request. It seems that prandom_u32() will keep its tracepoint,
> which means we definitely need this to make KCSAN compatible with
> tracing again.

Queued and pushed, thank you!

							Thanx, Paul

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-08-26 21:21 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-21 12:31 [PATCH] kcsan: Use tracing-safe version of prandom Marco Elver
2020-08-26 12:17 ` Marco Elver
2020-08-26 21:21   ` Paul E. McKenney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).