diff options
-rw-r--r-- | kernel/kcsan/core.c | 5 | ||||
-rw-r--r-- | kernel/kcsan/kcsan.h | 6 | ||||
-rw-r--r-- | kernel/kcsan/report.c | 31 |
3 files changed, 33 insertions, 9 deletions
diff --git a/kernel/kcsan/core.c b/kernel/kcsan/core.c index 6fe1513e1e6a..26709ea65c71 100644 --- a/kernel/kcsan/core.c +++ b/kernel/kcsan/core.c @@ -557,7 +557,8 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type) atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_ASSERT_FAILURES]); kcsan_report_known_origin(ptr, size, type, value_change, - watchpoint - watchpoints); + watchpoint - watchpoints, + old, new, access_mask); } else if (value_change == KCSAN_VALUE_CHANGE_TRUE) { /* Inferring a race, since the value should not have changed. */ @@ -566,7 +567,7 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type) atomic_long_inc(&kcsan_counters[KCSAN_COUNTER_ASSERT_FAILURES]); if (IS_ENABLED(CONFIG_KCSAN_REPORT_RACE_UNKNOWN_ORIGIN) || is_assert) - kcsan_report_unknown_origin(ptr, size, type); + kcsan_report_unknown_origin(ptr, size, type, old, new, access_mask); } /* diff --git a/kernel/kcsan/kcsan.h b/kernel/kcsan/kcsan.h index 572f119a19eb..f36e25c497ed 100644 --- a/kernel/kcsan/kcsan.h +++ b/kernel/kcsan/kcsan.h @@ -129,12 +129,14 @@ void kcsan_report_set_info(const volatile void *ptr, size_t size, int access_typ * thread. */ void kcsan_report_known_origin(const volatile void *ptr, size_t size, int access_type, - enum kcsan_value_change value_change, int watchpoint_idx); + enum kcsan_value_change value_change, int watchpoint_idx, + u64 old, u64 new, u64 mask); /* * No other thread was observed to race with the access, but the data value * before and after the stall differs. Reports a race of "unknown origin". */ -void kcsan_report_unknown_origin(const volatile void *ptr, size_t size, int access_type); +void kcsan_report_unknown_origin(const volatile void *ptr, size_t size, int access_type, + u64 old, u64 new, u64 mask); #endif /* _KERNEL_KCSAN_KCSAN_H */ diff --git a/kernel/kcsan/report.c b/kernel/kcsan/report.c index 50cee2357885..e37e4386f86d 100644 --- a/kernel/kcsan/report.c +++ b/kernel/kcsan/report.c @@ -327,7 +327,8 @@ static void print_verbose_info(struct task_struct *task) static void print_report(enum kcsan_value_change value_change, const struct access_info *ai, - const struct other_info *other_info) + const struct other_info *other_info, + u64 old, u64 new, u64 mask) { unsigned long stack_entries[NUM_STACK_ENTRIES] = { 0 }; int num_stack_entries = stack_trace_save(stack_entries, NUM_STACK_ENTRIES, 1); @@ -407,6 +408,24 @@ static void print_report(enum kcsan_value_change value_change, if (IS_ENABLED(CONFIG_KCSAN_VERBOSE)) print_verbose_info(current); + /* Print observed value change. */ + if (ai->size <= 8) { + int hex_len = ai->size * 2; + u64 diff = old ^ new; + + if (mask) + diff &= mask; + if (diff) { + pr_err("\n"); + pr_err("value changed: 0x%0*llx -> 0x%0*llx\n", + hex_len, old, hex_len, new); + if (mask) { + pr_err(" bits changed: 0x%0*llx with mask 0x%0*llx\n", + hex_len, diff, hex_len, mask); + } + } + } + /* Print report footer. */ pr_err("\n"); pr_err("Reported by Kernel Concurrency Sanitizer on:\n"); @@ -584,7 +603,8 @@ void kcsan_report_set_info(const volatile void *ptr, size_t size, int access_typ } void kcsan_report_known_origin(const volatile void *ptr, size_t size, int access_type, - enum kcsan_value_change value_change, int watchpoint_idx) + enum kcsan_value_change value_change, int watchpoint_idx, + u64 old, u64 new, u64 mask) { const struct access_info ai = prepare_access_info(ptr, size, access_type); struct other_info *other_info = &other_infos[watchpoint_idx]; @@ -608,7 +628,7 @@ void kcsan_report_known_origin(const volatile void *ptr, size_t size, int access * be done once we know the full stack trace in print_report(). */ if (value_change != KCSAN_VALUE_CHANGE_FALSE) - print_report(value_change, &ai, other_info); + print_report(value_change, &ai, other_info, old, new, mask); release_report(&flags, other_info); out: @@ -616,7 +636,8 @@ out: kcsan_enable_current(); } -void kcsan_report_unknown_origin(const volatile void *ptr, size_t size, int access_type) +void kcsan_report_unknown_origin(const volatile void *ptr, size_t size, int access_type, + u64 old, u64 new, u64 mask) { const struct access_info ai = prepare_access_info(ptr, size, access_type); unsigned long flags; @@ -625,7 +646,7 @@ void kcsan_report_unknown_origin(const volatile void *ptr, size_t size, int acce lockdep_off(); /* See kcsan_report_known_origin(). */ raw_spin_lock_irqsave(&report_lock, flags); - print_report(KCSAN_VALUE_CHANGE_TRUE, &ai, NULL); + print_report(KCSAN_VALUE_CHANGE_TRUE, &ai, NULL, old, new, mask); raw_spin_unlock_irqrestore(&report_lock, flags); lockdep_on(); |