Skip to content

Commit 92c209a

Browse files
melverIngo Molnar
authored andcommitted
kcsan: Improve IRQ state trace reporting
To improve the general usefulness of the IRQ state trace events with KCSAN enabled, save and restore the trace information when entering and exiting the KCSAN runtime as well as when generating a KCSAN report. Without this, reporting the IRQ trace events (whether via a KCSAN report or outside of KCSAN via a lockdep report) is rather useless due to continuously being touched by KCSAN. This is because if KCSAN is enabled, every instrumented memory access causes changes to IRQ trace events (either by KCSAN disabling/enabling interrupts or taking report_lock when generating a report). Before "lockdep: Prepare for NMI IRQ state tracking", KCSAN avoided touching the IRQ trace events via raw_local_irq_save/restore() and lockdep_off/on(). Fixes: 248591f ("kcsan: Make KCSAN compatible with new IRQ state tracking") Signed-off-by: Marco Elver <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 0584df9 commit 92c209a

File tree

4 files changed

+37
-0
lines changed

4 files changed

+37
-0
lines changed

include/linux/sched.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,8 +1184,12 @@ struct task_struct {
11841184
#ifdef CONFIG_KASAN
11851185
unsigned int kasan_depth;
11861186
#endif
1187+
11871188
#ifdef CONFIG_KCSAN
11881189
struct kcsan_ctx kcsan_ctx;
1190+
#ifdef CONFIG_TRACE_IRQFLAGS
1191+
struct irqtrace_events kcsan_save_irqtrace;
1192+
#endif
11891193
#endif
11901194

11911195
#ifdef CONFIG_FUNCTION_GRAPH_TRACER

kernel/kcsan/core.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,20 @@ static inline unsigned int get_delay(void)
291291
0);
292292
}
293293

294+
void kcsan_save_irqtrace(struct task_struct *task)
295+
{
296+
#ifdef CONFIG_TRACE_IRQFLAGS
297+
task->kcsan_save_irqtrace = task->irqtrace;
298+
#endif
299+
}
300+
301+
void kcsan_restore_irqtrace(struct task_struct *task)
302+
{
303+
#ifdef CONFIG_TRACE_IRQFLAGS
304+
task->irqtrace = task->kcsan_save_irqtrace;
305+
#endif
306+
}
307+
294308
/*
295309
* Pull everything together: check_access() below contains the performance
296310
* critical operations; the fast-path (including check_access) functions should
@@ -336,9 +350,11 @@ static noinline void kcsan_found_watchpoint(const volatile void *ptr,
336350
flags = user_access_save();
337351

338352
if (consumed) {
353+
kcsan_save_irqtrace(current);
339354
kcsan_report(ptr, size, type, KCSAN_VALUE_CHANGE_MAYBE,
340355
KCSAN_REPORT_CONSUMED_WATCHPOINT,
341356
watchpoint - watchpoints);
357+
kcsan_restore_irqtrace(current);
342358
} else {
343359
/*
344360
* The other thread may not print any diagnostics, as it has
@@ -396,6 +412,12 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
396412
goto out;
397413
}
398414

415+
/*
416+
* Save and restore the IRQ state trace touched by KCSAN, since KCSAN's
417+
* runtime is entered for every memory access, and potentially useful
418+
* information is lost if dirtied by KCSAN.
419+
*/
420+
kcsan_save_irqtrace(current);
399421
if (!kcsan_interrupt_watcher)
400422
local_irq_save(irq_flags);
401423

@@ -539,6 +561,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type)
539561
out_unlock:
540562
if (!kcsan_interrupt_watcher)
541563
local_irq_restore(irq_flags);
564+
kcsan_restore_irqtrace(current);
542565
out:
543566
user_access_restore(ua_flags);
544567
}

kernel/kcsan/kcsan.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#define _KERNEL_KCSAN_KCSAN_H
1010

1111
#include <linux/kcsan.h>
12+
#include <linux/sched.h>
1213

1314
/* The number of adjacent watchpoints to check. */
1415
#define KCSAN_CHECK_ADJACENT 1
@@ -22,6 +23,12 @@ extern unsigned int kcsan_udelay_interrupt;
2223
*/
2324
extern bool kcsan_enabled;
2425

26+
/*
27+
* Save/restore IRQ flags state trace dirtied by KCSAN.
28+
*/
29+
void kcsan_save_irqtrace(struct task_struct *task);
30+
void kcsan_restore_irqtrace(struct task_struct *task);
31+
2532
/*
2633
* Initialize debugfs file.
2734
*/

kernel/kcsan/report.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ static void print_verbose_info(struct task_struct *task)
308308
if (!task)
309309
return;
310310

311+
/* Restore IRQ state trace for printing. */
312+
kcsan_restore_irqtrace(task);
313+
311314
pr_err("\n");
312315
debug_show_held_locks(task);
313316
print_irqtrace_events(task);

0 commit comments

Comments
 (0)