]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
kcov: Add interrupt handling self test
authorDmitry Vyukov <dvyukov@google.com>
Tue, 11 Jun 2024 07:50:31 +0000 (09:50 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Thu, 8 Aug 2024 15:36:35 +0000 (17:36 +0200)
Add a boot self test that can catch sprious coverage from interrupts.
The coverage callback filters out interrupt code, but only after the
handler updates preempt count. Some code periodically leaks out
of that section and leads to spurious coverage.
Add a best-effort (but simple) test that is likely to catch such bugs.
If the test is enabled on CI systems that use KCOV, they should catch
any issues fast.

Signed-off-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Alexander Potapenko <glider@google.com>
Reviewed-by: Marco Elver <elver@google.com>
Reviewed-by: Andrey Konovalov <andreyknvl@gmail.com>
Link: https://lore.kernel.org/all/7662127c97e29da1a748ad1c1539dd7b65b737b2.1718092070.git.dvyukov@google.com
kernel/kcov.c
lib/Kconfig.debug

index f0a69d402066e12cdbf99f589ac6bbca02896978..d9d4a0c041855732b61d2d5e2771006bb4fb9209 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/fs.h>
 #include <linux/hashtable.h>
 #include <linux/init.h>
+#include <linux/jiffies.h>
 #include <linux/kmsan-checks.h>
 #include <linux/mm.h>
 #include <linux/preempt.h>
@@ -1058,6 +1059,32 @@ u64 kcov_common_handle(void)
 }
 EXPORT_SYMBOL(kcov_common_handle);
 
+#ifdef CONFIG_KCOV_SELFTEST
+static void __init selftest(void)
+{
+       unsigned long start;
+
+       pr_err("running self test\n");
+       /*
+        * Test that interrupts don't produce spurious coverage.
+        * The coverage callback filters out interrupt code, but only
+        * after the handler updates preempt count. Some code periodically
+        * leaks out of that section and leads to spurious coverage.
+        * It's hard to call the actual interrupt handler directly,
+        * so we just loop here for a bit waiting for a timer interrupt.
+        * We set kcov_mode to enable tracing, but don't setup the area,
+        * so any attempt to trace will crash. Note: we must not call any
+        * potentially traced functions in this region.
+        */
+       start = jiffies;
+       current->kcov_mode = KCOV_MODE_TRACE_PC;
+       while ((jiffies - start) * MSEC_PER_SEC / HZ < 300)
+               ;
+       current->kcov_mode = 0;
+       pr_err("done running self test\n");
+}
+#endif
+
 static int __init kcov_init(void)
 {
        int cpu;
@@ -1077,6 +1104,10 @@ static int __init kcov_init(void)
         */
        debugfs_create_file_unsafe("kcov", 0600, NULL, NULL, &kcov_fops);
 
+#ifdef CONFIG_KCOV_SELFTEST
+       selftest();
+#endif
+
        return 0;
 }
 
index a30c03a6617263f916f5c500c145a7cdae45bbdf..270e367b3e6f5931b5012d72dc0c86bdfae1285f 100644 (file)
@@ -2173,6 +2173,14 @@ config KCOV_IRQ_AREA_SIZE
          soft interrupts. This specifies the size of those areas in the
          number of unsigned long words.
 
+config KCOV_SELFTEST
+       bool "Perform short selftests on boot"
+       depends on KCOV
+       help
+         Run short KCOV coverage collection selftests on boot.
+         On test failure, causes the kernel to panic. Recommended to be
+         enabled, ensuring critical functionality works as intended.
+
 menuconfig RUNTIME_TESTING_MENU
        bool "Runtime Testing"
        default y