Skip to content

Commit b97efd5

Browse files
committed
Merge branch 'kcsan.2021.05.18a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu
Pull KCSAN updates from Paul McKenney. * 'kcsan.2021.05.18a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu: kcsan: Use URL link for pointing access-marking.txt kcsan: Document "value changed" line kcsan: Report observed value changes kcsan: Remove kcsan_report_type kcsan: Remove reporting indirection kcsan: Refactor access_info initialization kcsan: Fold panic() call into print_report() kcsan: Refactor passing watchpoint/other_info kcsan: Distinguish kcsan_report() calls kcsan: Simplify value change detection kcsan: Add pointer to access-marking.txt to data_race() bullet
2 parents a412897 + 117232c commit b97efd5

4 files changed

Lines changed: 166 additions & 188 deletions

File tree

Documentation/dev-tools/kcsan.rst

Lines changed: 39 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -27,75 +27,57 @@ Error reports
2727
A typical data race report looks like this::
2828

2929
==================================================================
30-
BUG: KCSAN: data-race in generic_permission / kernfs_refresh_inode
31-
32-
write to 0xffff8fee4c40700c of 4 bytes by task 175 on cpu 4:
33-
kernfs_refresh_inode+0x70/0x170
34-
kernfs_iop_permission+0x4f/0x90
35-
inode_permission+0x190/0x200
36-
link_path_walk.part.0+0x503/0x8e0
37-
path_lookupat.isra.0+0x69/0x4d0
38-
filename_lookup+0x136/0x280
39-
user_path_at_empty+0x47/0x60
40-
vfs_statx+0x9b/0x130
41-
__do_sys_newlstat+0x50/0xb0
42-
__x64_sys_newlstat+0x37/0x50
43-
do_syscall_64+0x85/0x260
44-
entry_SYSCALL_64_after_hwframe+0x44/0xa9
45-
46-
read to 0xffff8fee4c40700c of 4 bytes by task 166 on cpu 6:
47-
generic_permission+0x5b/0x2a0
48-
kernfs_iop_permission+0x66/0x90
49-
inode_permission+0x190/0x200
50-
link_path_walk.part.0+0x503/0x8e0
51-
path_lookupat.isra.0+0x69/0x4d0
52-
filename_lookup+0x136/0x280
53-
user_path_at_empty+0x47/0x60
54-
do_faccessat+0x11a/0x390
55-
__x64_sys_access+0x3c/0x50
56-
do_syscall_64+0x85/0x260
57-
entry_SYSCALL_64_after_hwframe+0x44/0xa9
30+
BUG: KCSAN: data-race in test_kernel_read / test_kernel_write
31+
32+
write to 0xffffffffc009a628 of 8 bytes by task 487 on cpu 0:
33+
test_kernel_write+0x1d/0x30
34+
access_thread+0x89/0xd0
35+
kthread+0x23e/0x260
36+
ret_from_fork+0x22/0x30
37+
38+
read to 0xffffffffc009a628 of 8 bytes by task 488 on cpu 6:
39+
test_kernel_read+0x10/0x20
40+
access_thread+0x89/0xd0
41+
kthread+0x23e/0x260
42+
ret_from_fork+0x22/0x30
43+
44+
value changed: 0x00000000000009a6 -> 0x00000000000009b2
5845

5946
Reported by Kernel Concurrency Sanitizer on:
60-
CPU: 6 PID: 166 Comm: systemd-journal Not tainted 5.3.0-rc7+ #1
61-
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014
47+
CPU: 6 PID: 488 Comm: access_thread Not tainted 5.12.0-rc2+ #1
48+
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014
6249
==================================================================
6350

6451
The header of the report provides a short summary of the functions involved in
6552
the race. It is followed by the access types and stack traces of the 2 threads
66-
involved in the data race.
53+
involved in the data race. If KCSAN also observed a value change, the observed
54+
old value and new value are shown on the "value changed" line respectively.
6755

6856
The other less common type of data race report looks like this::
6957

7058
==================================================================
71-
BUG: KCSAN: data-race in e1000_clean_rx_irq+0x551/0xb10
72-
73-
race at unknown origin, with read to 0xffff933db8a2ae6c of 1 bytes by interrupt on cpu 0:
74-
e1000_clean_rx_irq+0x551/0xb10
75-
e1000_clean+0x533/0xda0
76-
net_rx_action+0x329/0x900
77-
__do_softirq+0xdb/0x2db
78-
irq_exit+0x9b/0xa0
79-
do_IRQ+0x9c/0xf0
80-
ret_from_intr+0x0/0x18
81-
default_idle+0x3f/0x220
82-
arch_cpu_idle+0x21/0x30
83-
do_idle+0x1df/0x230
84-
cpu_startup_entry+0x14/0x20
85-
rest_init+0xc5/0xcb
86-
arch_call_rest_init+0x13/0x2b
87-
start_kernel+0x6db/0x700
59+
BUG: KCSAN: data-race in test_kernel_rmw_array+0x71/0xd0
60+
61+
race at unknown origin, with read to 0xffffffffc009bdb0 of 8 bytes by task 515 on cpu 2:
62+
test_kernel_rmw_array+0x71/0xd0
63+
access_thread+0x89/0xd0
64+
kthread+0x23e/0x260
65+
ret_from_fork+0x22/0x30
66+
67+
value changed: 0x0000000000002328 -> 0x0000000000002329
8868

8969
Reported by Kernel Concurrency Sanitizer on:
90-
CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.3.0-rc7+ #2
91-
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014
70+
CPU: 2 PID: 515 Comm: access_thread Not tainted 5.12.0-rc2+ #1
71+
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014
9272
==================================================================
9373

9474
This report is generated where it was not possible to determine the other
9575
racing thread, but a race was inferred due to the data value of the watched
96-
memory location having changed. These can occur either due to missing
97-
instrumentation or e.g. DMA accesses. These reports will only be generated if
98-
``CONFIG_KCSAN_REPORT_RACE_UNKNOWN_ORIGIN=y`` (selected by default).
76+
memory location having changed. These reports always show a "value changed"
77+
line. A common reason for reports of this type are missing instrumentation in
78+
the racing thread, but could also occur due to e.g. DMA accesses. Such reports
79+
are shown only if ``CONFIG_KCSAN_REPORT_RACE_UNKNOWN_ORIGIN=y``, which is
80+
enabled by default.
9981

10082
Selective analysis
10183
~~~~~~~~~~~~~~~~~~
@@ -106,7 +88,8 @@ the below options are available:
10688

10789
* KCSAN understands the ``data_race(expr)`` annotation, which tells KCSAN that
10890
any data races due to accesses in ``expr`` should be ignored and resulting
109-
behaviour when encountering a data race is deemed safe.
91+
behaviour when encountering a data race is deemed safe. Please see
92+
`"Marking Shared-Memory Accesses" in the LKMM`_ for more information.
11093

11194
* Disabling data race detection for entire functions can be accomplished by
11295
using the function attribute ``__no_kcsan``::
@@ -128,6 +111,8 @@ the below options are available:
128111

129112
KCSAN_SANITIZE := n
130113

114+
.. _"Marking Shared-Memory Accesses" in the LKMM: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/memory-model/Documentation/access-marking.txt
115+
131116
Furthermore, it is possible to tell KCSAN to show or hide entire classes of
132117
data races, depending on preferences. These can be changed via the following
133118
Kconfig options:

kernel/kcsan/core.c

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -380,9 +380,7 @@ static noinline void kcsan_found_watchpoint(const volatile void *ptr,
380380

381381
if (consumed) {
382382
kcsan_save_irqtrace(current);
383-
kcsan_report(ptr, size, type, KCSAN_VALUE_CHANGE_MAYBE,
384-
KCSAN_REPORT_CONSUMED_WATCHPOINT,
385-
watchpoint - watchpoints);
383+
kcsan_report_set_info(ptr, size, type, watchpoint - watchpoints);
386384
kcsan_restore_irqtrace(current);
387385
} else {
388386
/*
@@ -407,12 +405,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
407405
const bool is_write = (type & KCSAN_ACCESS_WRITE) != 0;
408406
const bool is_assert = (type & KCSAN_ACCESS_ASSERT) != 0;
409407
atomic_long_t *watchpoint;
410-
union {
411-
u8 _1;
412-
u16 _2;
413-
u32 _4;
414-
u64 _8;
415-
} expect_value;
408+
u64 old, new, diff;
416409
unsigned long access_mask;
417410
enum kcsan_value_change value_change = KCSAN_VALUE_CHANGE_MAYBE;
418411
unsigned long ua_flags = user_access_save();
@@ -468,19 +461,19 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
468461
* Read the current value, to later check and infer a race if the data
469462
* was modified via a non-instrumented access, e.g. from a device.
470463
*/
471-
expect_value._8 = 0;
464+
old = 0;
472465
switch (size) {
473466
case 1:
474-
expect_value._1 = READ_ONCE(*(const u8 *)ptr);
467+
old = READ_ONCE(*(const u8 *)ptr);
475468
break;
476469
case 2:
477-
expect_value._2 = READ_ONCE(*(const u16 *)ptr);
470+
old = READ_ONCE(*(const u16 *)ptr);
478471
break;
479472
case 4:
480-
expect_value._4 = READ_ONCE(*(const u32 *)ptr);
473+
old = READ_ONCE(*(const u32 *)ptr);
481474
break;
482475
case 8:
483-
expect_value._8 = READ_ONCE(*(const u64 *)ptr);
476+
old = READ_ONCE(*(const u64 *)ptr);
484477
break;
485478
default:
486479
break; /* ignore; we do not diff the values */
@@ -506,33 +499,30 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
506499
* racy access.
507500
*/
508501
access_mask = get_ctx()->access_mask;
502+
new = 0;
509503
switch (size) {
510504
case 1:
511-
expect_value._1 ^= READ_ONCE(*(const u8 *)ptr);
512-
if (access_mask)
513-
expect_value._1 &= (u8)access_mask;
505+
new = READ_ONCE(*(const u8 *)ptr);
514506
break;
515507
case 2:
516-
expect_value._2 ^= READ_ONCE(*(const u16 *)ptr);
517-
if (access_mask)
518-
expect_value._2 &= (u16)access_mask;
508+
new = READ_ONCE(*(const u16 *)ptr);
519509
break;
520510
case 4:
521-
expect_value._4 ^= READ_ONCE(*(const u32 *)ptr);
522-
if (access_mask)
523-
expect_value._4 &= (u32)access_mask;
511+
new = READ_ONCE(*(const u32 *)ptr);
524512
break;
525513
case 8:
526-
expect_value._8 ^= READ_ONCE(*(const u64 *)ptr);
527-
if (access_mask)
528-
expect_value._8 &= (u64)access_mask;
514+
new = READ_ONCE(*(const u64 *)ptr);
529515
break;
530516
default:
531517
break; /* ignore; we do not diff the values */
532518
}
533519

520+
diff = old ^ new;
521+
if (access_mask)
522+
diff &= access_mask;
523+
534524
/* Were we able to observe a value-change? */
535-
if (expect_value._8 != 0)
525+
if (diff != 0)
536526
value_change = KCSAN_VALUE_CHANGE_TRUE;
537527

538528
/* Check if this access raced with another. */
@@ -566,8 +556,9 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
566556
if (is_assert && value_change == KCSAN_VALUE_CHANGE_TRUE)
567557
atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_ASSERT_FAILURES]);
568558

569-
kcsan_report(ptr, size, type, value_change, KCSAN_REPORT_RACE_SIGNAL,
570-
watchpoint - watchpoints);
559+
kcsan_report_known_origin(ptr, size, type, value_change,
560+
watchpoint - watchpoints,
561+
old, new, access_mask);
571562
} else if (value_change == KCSAN_VALUE_CHANGE_TRUE) {
572563
/* Inferring a race, since the value should not have changed. */
573564

@@ -576,9 +567,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
576567
atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_ASSERT_FAILURES]);
577568

578569
if (IS_ENABLED(CONFIG_KCSAN_REPORT_RACE_UNKNOWN_ORIGIN) || is_assert)
579-
kcsan_report(ptr, size, type, KCSAN_VALUE_CHANGE_TRUE,
580-
KCSAN_REPORT_RACE_UNKNOWN_ORIGIN,
581-
watchpoint - watchpoints);
570+
kcsan_report_unknown_origin(ptr, size, type, old, new, access_mask);
582571
}
583572

584573
/*

kernel/kcsan/kcsan.h

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -116,30 +116,27 @@ enum kcsan_value_change {
116116
KCSAN_VALUE_CHANGE_TRUE,
117117
};
118118

119-
enum kcsan_report_type {
120-
/*
121-
* The thread that set up the watchpoint and briefly stalled was
122-
* signalled that another thread triggered the watchpoint.
123-
*/
124-
KCSAN_REPORT_RACE_SIGNAL,
125-
126-
/*
127-
* A thread found and consumed a matching watchpoint.
128-
*/
129-
KCSAN_REPORT_CONSUMED_WATCHPOINT,
119+
/*
120+
* The calling thread hit and consumed a watchpoint: set the access information
121+
* to be consumed by the reporting thread. No report is printed yet.
122+
*/
123+
void kcsan_report_set_info(const volatile void *ptr, size_t size, int access_type,
124+
int watchpoint_idx);
130125

131-
/*
132-
* No other thread was observed to race with the access, but the data
133-
* value before and after the stall differs.
134-
*/
135-
KCSAN_REPORT_RACE_UNKNOWN_ORIGIN,
136-
};
126+
/*
127+
* The calling thread observed that the watchpoint it set up was hit and
128+
* consumed: print the full report based on information set by the racing
129+
* thread.
130+
*/
131+
void kcsan_report_known_origin(const volatile void *ptr, size_t size, int access_type,
132+
enum kcsan_value_change value_change, int watchpoint_idx,
133+
u64 old, u64 new, u64 mask);
137134

138135
/*
139-
* Print a race report from thread that encountered the race.
136+
* No other thread was observed to race with the access, but the data value
137+
* before and after the stall differs. Reports a race of "unknown origin".
140138
*/
141-
extern void kcsan_report(const volatile void *ptr, size_t size, int access_type,
142-
enum kcsan_value_change value_change,
143-
enum kcsan_report_type type, int watchpoint_idx);
139+
void kcsan_report_unknown_origin(const volatile void *ptr, size_t size, int access_type,
140+
u64 old, u64 new, u64 mask);
144141

145142
#endif /* _KERNEL_KCSAN_KCSAN_H */

0 commit comments

Comments
 (0)