If a watcher deliberately disables interrupts (either by user choice, or because we're dealing with a scoped reordered access) to avoid detecting any data races in interrupts, NMIs are still able to fire. When we set up a watchpoint on a scoped reordered access, we disabled interrupts because the same CPU cannot observe reordering of its own accesses. To ensure we observe no false positives from NMIs, disable access checking for interrupt contexts as well.
Unified · Split
| @@ -585,8 +585,14 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type, unsigned · 584 unmodified lines | ||
| 585 | 585 | * information is lost if dirtied by KCSAN. |
| 586 | 586 | */ |
| 587 | 587 | kcsan_save_irqtrace(current); |
| 588 | − if (!interrupt_watcher) | |
| 588 | + if (!interrupt_watcher) { | |
| 589 | 589 | local_irq_save(irq_flags); |
| 590 | + /* | |
| 591 | + * NMIs can still fire, disable checking for all interrupt | |
| 592 | + * contexts. | |
| 593 | + */ | |
| 594 | + raw_cpu_ptr(&kcsan_cpu_ctx)->disable_count++; | |
| 595 | + } | |
| 590 | 596 | |
| 591 | 597 | watchpoint = insert_watchpoint((unsigned long)ptr, size, is_write); |
| 592 | 598 | if (watchpoint == NULL) { |
| @@ -699,8 +705,10 @@ kcsan_setup_watchpoint(const volatile void *ptr, size_t size, int type, unsigned · 106 unmodified lines | ||
| 699 | 705 | atomic_long_dec(&kcsan_counters[KCSAN_COUNTER_USED_WATCHPOINTS]); |
| 700 | 706 | |
| 701 | 707 | out_unlock: |
| 702 | − if (!interrupt_watcher) | |
| 708 | + if (!interrupt_watcher) { | |
| 709 | + raw_cpu_ptr(&kcsan_cpu_ctx)->disable_count--; | |
| 703 | 710 | local_irq_restore(irq_flags); |
| 711 | + } | |
| 704 | 712 | kcsan_restore_irqtrace(current); |
| 705 | 713 | ctx->disable_scoped--; |
| 706 | 714 | |