Skip to content

Commit 49f72d5

Browse files
melverpaulmckrcu
authored andcommitted
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 <elver@google.com> Acked-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
1 parent 08cac60 commit 49f72d5

5 files changed

Lines changed: 89 additions & 32 deletions

File tree

Documentation/dev-tools/kcsan.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,14 @@ Kconfig options:
127127
causes KCSAN to not report data races due to conflicts where the only plain
128128
accesses are aligned writes up to word size.
129129

130+
* ``CONFIG_KCSAN_PERMISSIVE``: Enable additional permissive rules to ignore
131+
certain classes of common data races. Unlike the above, the rules are more
132+
complex involving value-change patterns, access type, and address. This
133+
option depends on ``CONFIG_KCSAN_REPORT_VALUE_CHANGE_ONLY=y``. For details
134+
please see the ``kernel/kcsan/permissive.h``. Testers and maintainers that
135+
only focus on reports from specific subsystems and not the whole kernel are
136+
recommended to disable this option.
137+
130138
To use the strictest possible rules, select ``CONFIG_KCSAN_STRICT=y``, which
131139
configures KCSAN to follow the Linux-kernel memory consistency model (LKMM) as
132140
closely as possible.

kernel/kcsan/atomic.h

Lines changed: 0 additions & 23 deletions
This file was deleted.

kernel/kcsan/core.c

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020
#include <linux/sched.h>
2121
#include <linux/uaccess.h>
2222

23-
#include "atomic.h"
2423
#include "encoding.h"
2524
#include "kcsan.h"
25+
#include "permissive.h"
2626

2727
static bool kcsan_early_enable = IS_ENABLED(CONFIG_KCSAN_EARLY_ENABLE);
2828
unsigned int kcsan_udelay_task = CONFIG_KCSAN_UDELAY_TASK;
@@ -353,6 +353,7 @@ static noinline void kcsan_found_watchpoint(const volatile void *ptr,
353353
atomic_long_t *watchpoint,
354354
long encoded_watchpoint)
355355
{
356+
const bool is_assert = (type & KCSAN_ACCESS_ASSERT) != 0;
356357
struct kcsan_ctx *ctx = get_ctx();
357358
unsigned long flags;
358359
bool consumed;
@@ -374,6 +375,16 @@ static noinline void kcsan_found_watchpoint(const volatile void *ptr,
374375
if (ctx->access_mask)
375376
return;
376377

378+
/*
379+
* If the other thread does not want to ignore the access, and there was
380+
* a value change as a result of this thread's operation, we will still
381+
* generate a report of unknown origin.
382+
*
383+
* Use CONFIG_KCSAN_REPORT_RACE_UNKNOWN_ORIGIN=n to filter.
384+
*/
385+
if (!is_assert && kcsan_ignore_address(ptr))
386+
return;
387+
377388
/*
378389
* Consuming the watchpoint must be guarded by kcsan_is_enabled() to
379390
* avoid erroneously triggering reports if the context is disabled.
@@ -396,7 +407,7 @@ static noinline void kcsan_found_watchpoint(const volatile void *ptr,
396407
atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_REPORT_RACES]);
397408
}
398409

399-
if ((type & KCSAN_ACCESS_ASSERT) != 0)
410+
if (is_assert)
400411
atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_ASSERT_FAILURES]);
401412
else
402413
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)
427438
goto out;
428439

429440
/*
430-
* Special atomic rules: unlikely to be true, so we check them here in
431-
* the slow-path, and not in the fast-path in is_atomic(). Call after
432-
* kcsan_is_enabled(), as we may access memory that is not yet
433-
* initialized during early boot.
441+
* Check to-ignore addresses after kcsan_is_enabled(), as we may access
442+
* memory that is not yet initialized during early boot.
434443
*/
435-
if (!is_assert && kcsan_is_atomic_special(ptr))
444+
if (!is_assert && kcsan_ignore_address(ptr))
436445
goto out;
437446

438447
if (!check_encodable((unsigned long)ptr, size)) {
@@ -518,8 +527,14 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
518527
if (access_mask)
519528
diff &= access_mask;
520529

521-
/* Were we able to observe a value-change? */
522-
if (diff != 0)
530+
/*
531+
* Check if we observed a value change.
532+
*
533+
* Also check if the data race should be ignored (the rules depend on
534+
* non-zero diff); if it is to be ignored, the below rules for
535+
* KCSAN_VALUE_CHANGE_MAYBE apply.
536+
*/
537+
if (diff && !kcsan_ignore_data_race(size, type, old, new, diff))
523538
value_change = KCSAN_VALUE_CHANGE_TRUE;
524539

525540
/* Check if this access raced with another. */

kernel/kcsan/permissive.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Special rules for ignoring entire classes of data-racy memory accesses. None
4+
* of the rules here imply that such data races are generally safe!
5+
*
6+
* All rules in this file can be configured via CONFIG_KCSAN_PERMISSIVE. Keep
7+
* them separate from core code to make it easier to audit.
8+
*
9+
* Copyright (C) 2019, Google LLC.
10+
*/
11+
12+
#ifndef _KERNEL_KCSAN_PERMISSIVE_H
13+
#define _KERNEL_KCSAN_PERMISSIVE_H
14+
15+
#include <linux/types.h>
16+
17+
/*
18+
* Access ignore rules based on address.
19+
*/
20+
static __always_inline bool kcsan_ignore_address(const volatile void *ptr)
21+
{
22+
if (!IS_ENABLED(CONFIG_KCSAN_PERMISSIVE))
23+
return false;
24+
25+
return false;
26+
}
27+
28+
/*
29+
* Data race ignore rules based on access type and value change patterns.
30+
*/
31+
static bool
32+
kcsan_ignore_data_race(size_t size, int type, u64 old, u64 new, u64 diff)
33+
{
34+
if (!IS_ENABLED(CONFIG_KCSAN_PERMISSIVE))
35+
return false;
36+
37+
/*
38+
* Rules here are only for plain read accesses, so that we still report
39+
* data races between plain read-write accesses.
40+
*/
41+
if (type || size > sizeof(long))
42+
return false;
43+
44+
return false;
45+
}
46+
47+
#endif /* _KERNEL_KCSAN_PERMISSIVE_H */

lib/Kconfig.kcsan

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,4 +231,14 @@ config KCSAN_IGNORE_ATOMICS
231231
due to two conflicting plain writes will be reported (aligned and
232232
unaligned, if CONFIG_KCSAN_ASSUME_PLAIN_WRITES_ATOMIC=n).
233233

234+
config KCSAN_PERMISSIVE
235+
bool "Enable all additional permissive rules"
236+
depends on KCSAN_REPORT_VALUE_CHANGE_ONLY
237+
help
238+
Enable additional permissive rules to ignore certain classes of data
239+
races (also see kernel/kcsan/permissive.h). None of the permissive
240+
rules imply that such data races are generally safe, but can be used
241+
to further reduce reported data races due to data-racy patterns
242+
common across the kernel.
243+
234244
endif # KCSAN

0 commit comments

Comments
 (0)