From eb32f9f990d974a7878a8792cee9bb821720c24b Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 7 Jun 2021 14:56:47 +0200 Subject: kcsan: Improve some Kconfig comments Improve comment for CC_HAS_TSAN_COMPOUND_READ_BEFORE_WRITE. Also shorten the comment above the "strictness" configuration options. Acked-by: Mark Rutland Signed-off-by: Marco Elver Signed-off-by: Paul E. McKenney --- lib/Kconfig.kcsan | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/Kconfig.kcsan b/lib/Kconfig.kcsan index 0440f373248e..6152fbd5cbb4 100644 --- a/lib/Kconfig.kcsan +++ b/lib/Kconfig.kcsan @@ -40,10 +40,14 @@ menuconfig KCSAN if KCSAN -# Compiler capabilities that should not fail the test if they are unavailable. config CC_HAS_TSAN_COMPOUND_READ_BEFORE_WRITE def_bool (CC_IS_CLANG && $(cc-option,-fsanitize=thread -mllvm -tsan-compound-read-before-write=1)) || \ (CC_IS_GCC && $(cc-option,-fsanitize=thread --param tsan-compound-read-before-write=1)) + help + The compiler instruments plain compound read-write operations + differently (++, --, +=, -=, |=, &=, etc.), which allows KCSAN to + distinguish them from other plain accesses. This is currently + supported by Clang 12 or later. config KCSAN_VERBOSE bool "Show verbose reports with more information about system state" @@ -169,13 +173,9 @@ config KCSAN_REPORT_ONCE_IN_MS reporting to avoid flooding the console with reports. Setting this to 0 disables rate limiting. -# The main purpose of the below options is to control reported data races (e.g. -# in fuzzer configs), and are not expected to be switched frequently by other -# users. We could turn some of them into boot parameters, but given they should -# not be switched normally, let's keep them here to simplify configuration. -# -# The defaults below are chosen to be very conservative, and may miss certain -# bugs. +# The main purpose of the below options is to control reported data races, and +# are not expected to be switched frequently by non-testers or at runtime. +# The defaults are chosen to be conservative, and can miss certain bugs. config KCSAN_REPORT_RACE_UNKNOWN_ORIGIN bool "Report races of unknown origin" -- cgit v1.2.3 From a7a73697360ea81244eea550138b8f614348860c Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 7 Jun 2021 14:56:48 +0200 Subject: kcsan: Remove CONFIG_KCSAN_DEBUG By this point CONFIG_KCSAN_DEBUG is pretty useless, as the system just isn't usable with it due to spamming console (I imagine a randconfig test robot will run into this sooner or later). Remove it. Back in 2019 I used it occasionally to record traces of watchpoints and verify the encoding is correct, but these days we have proper tests. If something similar is needed in future, just add it back ad-hoc. Signed-off-by: Marco Elver Acked-by: Mark Rutland Signed-off-by: Paul E. McKenney --- kernel/kcsan/core.c | 9 --------- lib/Kconfig.kcsan | 3 --- 2 files changed, 12 deletions(-) (limited to 'lib') diff --git a/kernel/kcsan/core.c b/kernel/kcsan/core.c index 26709ea65c71..d92977ede7e1 100644 --- a/kernel/kcsan/core.c +++ b/kernel/kcsan/core.c @@ -479,15 +479,6 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type) break; /* ignore; we do not diff the values */ } - if (IS_ENABLED(CONFIG_KCSAN_DEBUG)) { - kcsan_disable_current(); - pr_err("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. diff --git a/lib/Kconfig.kcsan b/lib/Kconfig.kcsan index 6152fbd5cbb4..5304f211f81f 100644 --- a/lib/Kconfig.kcsan +++ b/lib/Kconfig.kcsan @@ -62,9 +62,6 @@ config KCSAN_VERBOSE generated from any one of them, system stability may suffer due to deadlocks or recursion. If in doubt, say N. -config KCSAN_DEBUG - bool "Debugging of KCSAN internals" - config KCSAN_SELFTEST bool "Perform short selftests on boot" default y -- cgit v1.2.3 From e675d2533a74acfa95c62e7bb088335866f44fd2 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 7 Jun 2021 14:56:49 +0200 Subject: kcsan: Introduce CONFIG_KCSAN_STRICT Add a simpler Kconfig variable to configure KCSAN's "strict" mode. This makes it simpler in documentation or messages to suggest just a single configuration option to select the strictest checking mode (vs. currently having to list several options). Signed-off-by: Marco Elver Acked-by: Mark Rutland Signed-off-by: Paul E. McKenney --- Documentation/dev-tools/kcsan.rst | 4 ++++ lib/Kconfig.kcsan | 10 ++++++++++ 2 files changed, 14 insertions(+) (limited to 'lib') diff --git a/Documentation/dev-tools/kcsan.rst b/Documentation/dev-tools/kcsan.rst index 6a600cf8430b..69dc9c502ccc 100644 --- a/Documentation/dev-tools/kcsan.rst +++ b/Documentation/dev-tools/kcsan.rst @@ -127,6 +127,10 @@ Kconfig options: causes KCSAN to not report data races due to conflicts where the only plain accesses are aligned writes up to word size. +To use the strictest possible rules, select ``CONFIG_KCSAN_STRICT=y``, which +configures KCSAN to follow the Linux-kernel memory consistency model (LKMM) as +closely as possible. + DebugFS interface ~~~~~~~~~~~~~~~~~ diff --git a/lib/Kconfig.kcsan b/lib/Kconfig.kcsan index 5304f211f81f..c76fbb3ee09e 100644 --- a/lib/Kconfig.kcsan +++ b/lib/Kconfig.kcsan @@ -183,9 +183,17 @@ config KCSAN_REPORT_RACE_UNKNOWN_ORIGIN reported if it was only possible to infer a race due to a data value change while an access is being delayed on a watchpoint. +config KCSAN_STRICT + bool "Strict data-race checking" + help + KCSAN will report data races with the strictest possible rules, which + closely aligns with the rules defined by the Linux-kernel memory + consistency model (LKMM). + config KCSAN_REPORT_VALUE_CHANGE_ONLY bool "Only report races where watcher observed a data value change" default y + depends on !KCSAN_STRICT help If enabled and a conflicting write is observed via a watchpoint, but the data value of the memory location was observed to remain @@ -194,6 +202,7 @@ config KCSAN_REPORT_VALUE_CHANGE_ONLY config KCSAN_ASSUME_PLAIN_WRITES_ATOMIC bool "Assume that plain aligned writes up to word size are atomic" default y + depends on !KCSAN_STRICT help Assume that plain aligned writes up to word size are atomic by default, and also not subject to other unsafe compiler optimizations @@ -206,6 +215,7 @@ config KCSAN_ASSUME_PLAIN_WRITES_ATOMIC config KCSAN_IGNORE_ATOMICS bool "Do not instrument marked atomic accesses" + depends on !KCSAN_STRICT help Never instrument marked atomic accesses. This option can be used for additional filtering. Conflicting marked atomic reads and plain -- cgit v1.2.3 From 49f72d5358dd3c0d28bcd2232c513000b15480f0 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 7 Jun 2021 14:56:51 +0200 Subject: kcsan: Rework atomic.h into permissive.h Rework atomic.h into permissive.h to better reflect its purpose, and introduce kcsan_ignore_address() and kcsan_ignore_data_race(). Introduce CONFIG_KCSAN_PERMISSIVE and update the stub functions in preparation for subsequent changes. As before, developers who choose to use KCSAN in "strict" mode will see all data races and are not affected. Furthermore, by relying on the value-change filter logic for kcsan_ignore_data_race(), even if the permissive rules are enabled, the opt-outs in report.c:skip_report() override them (such as for RCU-related functions by default). The option CONFIG_KCSAN_PERMISSIVE is disabled by default, so that the documented default behaviour of KCSAN does not change. Instead, like CONFIG_KCSAN_IGNORE_ATOMICS, the option needs to be explicitly opted in. Signed-off-by: Marco Elver Acked-by: Mark Rutland Signed-off-by: Paul E. McKenney --- Documentation/dev-tools/kcsan.rst | 8 +++++++ kernel/kcsan/atomic.h | 23 ------------------- kernel/kcsan/core.c | 33 +++++++++++++++++++-------- kernel/kcsan/permissive.h | 47 +++++++++++++++++++++++++++++++++++++++ lib/Kconfig.kcsan | 10 +++++++++ 5 files changed, 89 insertions(+), 32 deletions(-) delete mode 100644 kernel/kcsan/atomic.h create mode 100644 kernel/kcsan/permissive.h (limited to 'lib') diff --git a/Documentation/dev-tools/kcsan.rst b/Documentation/dev-tools/kcsan.rst index 69dc9c502ccc..7db43c7c09b8 100644 --- a/Documentation/dev-tools/kcsan.rst +++ b/Documentation/dev-tools/kcsan.rst @@ -127,6 +127,14 @@ Kconfig options: causes KCSAN to not report data races due to conflicts where the only plain accesses are aligned writes up to word size. +* ``CONFIG_KCSAN_PERMISSIVE``: Enable additional permissive rules to ignore + certain classes of common data races. Unlike the above, the rules are more + complex involving value-change patterns, access type, and address. This + option depends on ``CONFIG_KCSAN_REPORT_VALUE_CHANGE_ONLY=y``. For details + please see the ``kernel/kcsan/permissive.h``. Testers and maintainers that + only focus on reports from specific subsystems and not the whole kernel are + recommended to disable this option. + To use the strictest possible rules, select ``CONFIG_KCSAN_STRICT=y``, which configures KCSAN to follow the Linux-kernel memory consistency model (LKMM) as closely as possible. diff --git a/kernel/kcsan/atomic.h b/kernel/kcsan/atomic.h deleted file mode 100644 index 530ae1bda8e7..000000000000 --- a/kernel/kcsan/atomic.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Rules for implicitly atomic memory accesses. - * - * Copyright (C) 2019, Google LLC. - */ - -#ifndef _KERNEL_KCSAN_ATOMIC_H -#define _KERNEL_KCSAN_ATOMIC_H - -#include - -/* - * Special rules for certain memory where concurrent conflicting accesses are - * common, however, the current convention is to not mark them; returns true if - * access to @ptr should be considered atomic. Called from slow-path. - */ -static bool kcsan_is_atomic_special(const volatile void *ptr) -{ - return false; -} - -#endif /* _KERNEL_KCSAN_ATOMIC_H */ diff --git a/kernel/kcsan/core.c b/kernel/kcsan/core.c index 906100923b88..439edb9dcbb1 100644 --- a/kernel/kcsan/core.c +++ b/kernel/kcsan/core.c @@ -20,9 +20,9 @@ #include #include -#include "atomic.h" #include "encoding.h" #include "kcsan.h" +#include "permissive.h" static bool kcsan_early_enable = IS_ENABLED(CONFIG_KCSAN_EARLY_ENABLE); unsigned int kcsan_udelay_task = CONFIG_KCSAN_UDELAY_TASK; @@ -353,6 +353,7 @@ static noinline void kcsan_found_watchpoint(const volatile void *ptr, atomic_long_t *watchpoint, long encoded_watchpoint) { + const bool is_assert = (type & KCSAN_ACCESS_ASSERT) != 0; struct kcsan_ctx *ctx = get_ctx(); unsigned long flags; bool consumed; @@ -374,6 +375,16 @@ static noinline void kcsan_found_watchpoint(const volatile void *ptr, if (ctx->access_mask) return; + /* + * If the other thread does not want to ignore the access, and there was + * a value change as a result of this thread's operation, we will still + * generate a report of unknown origin. + * + * Use CONFIG_KCSAN_REPORT_RACE_UNKNOWN_ORIGIN=n to filter. + */ + if (!is_assert && kcsan_ignore_address(ptr)) + return; + /* * Consuming the watchpoint must be guarded by kcsan_is_enabled() to * avoid erroneously triggering reports if the context is disabled. @@ -396,7 +407,7 @@ static noinline void kcsan_found_watchpoint(const volatile void *ptr, atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_REPORT_RACES]); } - if ((type & KCSAN_ACCESS_ASSERT) != 0) + if (is_assert) atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_ASSERT_FAILURES]); else atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_DATA_RACES]); @@ -427,12 +438,10 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type) goto out; /* - * Special atomic rules: unlikely to be true, so we check them here in - * the slow-path, and not in the fast-path in is_atomic(). Call after - * kcsan_is_enabled(), as we may access memory that is not yet - * initialized during early boot. + * Check to-ignore addresses after kcsan_is_enabled(), as we may access + * memory that is not yet initialized during early boot. */ - if (!is_assert && kcsan_is_atomic_special(ptr)) + if (!is_assert && kcsan_ignore_address(ptr)) goto out; if (!check_encodable((unsigned long)ptr, size)) { @@ -518,8 +527,14 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type) if (access_mask) diff &= access_mask; - /* Were we able to observe a value-change? */ - if (diff != 0) + /* + * Check if we observed a value change. + * + * Also check if the data race should be ignored (the rules depend on + * non-zero diff); if it is to be ignored, the below rules for + * KCSAN_VALUE_CHANGE_MAYBE apply. + */ + if (diff && !kcsan_ignore_data_race(size, type, old, new, diff)) value_change = KCSAN_VALUE_CHANGE_TRUE; /* Check if this access raced with another. */ diff --git a/kernel/kcsan/permissive.h b/kernel/kcsan/permissive.h new file mode 100644 index 000000000000..f90e30800c11 --- /dev/null +++ b/kernel/kcsan/permissive.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Special rules for ignoring entire classes of data-racy memory accesses. None + * of the rules here imply that such data races are generally safe! + * + * All rules in this file can be configured via CONFIG_KCSAN_PERMISSIVE. Keep + * them separate from core code to make it easier to audit. + * + * Copyright (C) 2019, Google LLC. + */ + +#ifndef _KERNEL_KCSAN_PERMISSIVE_H +#define _KERNEL_KCSAN_PERMISSIVE_H + +#include + +/* + * Access ignore rules based on address. + */ +static __always_inline bool kcsan_ignore_address(const volatile void *ptr) +{ + if (!IS_ENABLED(CONFIG_KCSAN_PERMISSIVE)) + return false; + + return false; +} + +/* + * Data race ignore rules based on access type and value change patterns. + */ +static bool +kcsan_ignore_data_race(size_t size, int type, u64 old, u64 new, u64 diff) +{ + if (!IS_ENABLED(CONFIG_KCSAN_PERMISSIVE)) + return false; + + /* + * Rules here are only for plain read accesses, so that we still report + * data races between plain read-write accesses. + */ + if (type || size > sizeof(long)) + return false; + + return false; +} + +#endif /* _KERNEL_KCSAN_PERMISSIVE_H */ diff --git a/lib/Kconfig.kcsan b/lib/Kconfig.kcsan index c76fbb3ee09e..26f03c754d39 100644 --- a/lib/Kconfig.kcsan +++ b/lib/Kconfig.kcsan @@ -231,4 +231,14 @@ config KCSAN_IGNORE_ATOMICS due to two conflicting plain writes will be reported (aligned and unaligned, if CONFIG_KCSAN_ASSUME_PLAIN_WRITES_ATOMIC=n). +config KCSAN_PERMISSIVE + bool "Enable all additional permissive rules" + depends on KCSAN_REPORT_VALUE_CHANGE_ONLY + help + Enable additional permissive rules to ignore certain classes of data + races (also see kernel/kcsan/permissive.h). None of the permissive + rules imply that such data races are generally safe, but can be used + to further reduce reported data races due to data-racy patterns + common across the kernel. + endif # KCSAN -- cgit v1.2.3 From e04938042d77addc7f41d983aebea125cddbed33 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Tue, 15 Jun 2021 20:39:38 +0200 Subject: kcsan: Make strict mode imply interruptible watchers If CONFIG_KCSAN_STRICT=y, select CONFIG_KCSAN_INTERRUPT_WATCHER as well. With interruptible watchers, we'll also report same-CPU data races; if we requested strict mode, we might as well show these, too. Suggested-by: Paul E. McKenney Signed-off-by: Marco Elver Signed-off-by: Paul E. McKenney --- lib/Kconfig.kcsan | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/Kconfig.kcsan b/lib/Kconfig.kcsan index 26f03c754d39..e0a93ffdef30 100644 --- a/lib/Kconfig.kcsan +++ b/lib/Kconfig.kcsan @@ -150,7 +150,8 @@ config KCSAN_SKIP_WATCH_RANDOMIZE KCSAN_WATCH_SKIP. config KCSAN_INTERRUPT_WATCHER - bool "Interruptible watchers" + bool "Interruptible watchers" if !KCSAN_STRICT + default KCSAN_STRICT help If enabled, a task that set up a watchpoint may be interrupted while delayed. This option will allow KCSAN to detect races between -- cgit v1.2.3