xref: /openbmc/linux/mm/kmsan/kmsan_test.c (revision 1f6ab566)
18ed691b0SAlexander Potapenko // SPDX-License-Identifier: GPL-2.0
28ed691b0SAlexander Potapenko /*
38ed691b0SAlexander Potapenko  * Test cases for KMSAN.
48ed691b0SAlexander Potapenko  * For each test case checks the presence (or absence) of generated reports.
58ed691b0SAlexander Potapenko  * Relies on 'console' tracepoint to capture reports as they appear in the
68ed691b0SAlexander Potapenko  * kernel log.
78ed691b0SAlexander Potapenko  *
88ed691b0SAlexander Potapenko  * Copyright (C) 2021-2022, Google LLC.
98ed691b0SAlexander Potapenko  * Author: Alexander Potapenko <glider@google.com>
108ed691b0SAlexander Potapenko  *
118ed691b0SAlexander Potapenko  */
128ed691b0SAlexander Potapenko 
138ed691b0SAlexander Potapenko #include <kunit/test.h>
148ed691b0SAlexander Potapenko #include "kmsan.h"
158ed691b0SAlexander Potapenko 
168ed691b0SAlexander Potapenko #include <linux/jiffies.h>
178ed691b0SAlexander Potapenko #include <linux/kernel.h>
188ed691b0SAlexander Potapenko #include <linux/kmsan.h>
198ed691b0SAlexander Potapenko #include <linux/mm.h>
208ed691b0SAlexander Potapenko #include <linux/random.h>
218ed691b0SAlexander Potapenko #include <linux/slab.h>
228ed691b0SAlexander Potapenko #include <linux/spinlock.h>
238ed691b0SAlexander Potapenko #include <linux/string.h>
248ed691b0SAlexander Potapenko #include <linux/tracepoint.h>
25aaa746adSArnd Bergmann #include <linux/vmalloc.h>
268ed691b0SAlexander Potapenko #include <trace/events/printk.h>
278ed691b0SAlexander Potapenko 
288ed691b0SAlexander Potapenko static DEFINE_PER_CPU(int, per_cpu_var);
298ed691b0SAlexander Potapenko 
308ed691b0SAlexander Potapenko /* Report as observed from console. */
318ed691b0SAlexander Potapenko static struct {
328ed691b0SAlexander Potapenko 	spinlock_t lock;
338ed691b0SAlexander Potapenko 	bool available;
348ed691b0SAlexander Potapenko 	bool ignore; /* Stop console output collection. */
358ed691b0SAlexander Potapenko 	char header[256];
368ed691b0SAlexander Potapenko } observed = {
378ed691b0SAlexander Potapenko 	.lock = __SPIN_LOCK_UNLOCKED(observed.lock),
388ed691b0SAlexander Potapenko };
398ed691b0SAlexander Potapenko 
408ed691b0SAlexander Potapenko /* Probe for console output: obtains observed lines of interest. */
probe_console(void * ignore,const char * buf,size_t len)418ed691b0SAlexander Potapenko static void probe_console(void *ignore, const char *buf, size_t len)
428ed691b0SAlexander Potapenko {
438ed691b0SAlexander Potapenko 	unsigned long flags;
448ed691b0SAlexander Potapenko 
458ed691b0SAlexander Potapenko 	if (observed.ignore)
468ed691b0SAlexander Potapenko 		return;
478ed691b0SAlexander Potapenko 	spin_lock_irqsave(&observed.lock, flags);
488ed691b0SAlexander Potapenko 
498ed691b0SAlexander Potapenko 	if (strnstr(buf, "BUG: KMSAN: ", len)) {
508ed691b0SAlexander Potapenko 		/*
518ed691b0SAlexander Potapenko 		 * KMSAN report and related to the test.
528ed691b0SAlexander Potapenko 		 *
538ed691b0SAlexander Potapenko 		 * The provided @buf is not NUL-terminated; copy no more than
548ed691b0SAlexander Potapenko 		 * @len bytes and let strscpy() add the missing NUL-terminator.
558ed691b0SAlexander Potapenko 		 */
568ed691b0SAlexander Potapenko 		strscpy(observed.header, buf,
578ed691b0SAlexander Potapenko 			min(len + 1, sizeof(observed.header)));
588ed691b0SAlexander Potapenko 		WRITE_ONCE(observed.available, true);
598ed691b0SAlexander Potapenko 		observed.ignore = true;
608ed691b0SAlexander Potapenko 	}
618ed691b0SAlexander Potapenko 	spin_unlock_irqrestore(&observed.lock, flags);
628ed691b0SAlexander Potapenko }
638ed691b0SAlexander Potapenko 
648ed691b0SAlexander Potapenko /* Check if a report related to the test exists. */
report_available(void)658ed691b0SAlexander Potapenko static bool report_available(void)
668ed691b0SAlexander Potapenko {
678ed691b0SAlexander Potapenko 	return READ_ONCE(observed.available);
688ed691b0SAlexander Potapenko }
698ed691b0SAlexander Potapenko 
708ed691b0SAlexander Potapenko /* Information we expect in a report. */
718ed691b0SAlexander Potapenko struct expect_report {
728ed691b0SAlexander Potapenko 	const char *error_type; /* Error type. */
738ed691b0SAlexander Potapenko 	/*
748ed691b0SAlexander Potapenko 	 * Kernel symbol from the error header, or NULL if no report is
758ed691b0SAlexander Potapenko 	 * expected.
768ed691b0SAlexander Potapenko 	 */
778ed691b0SAlexander Potapenko 	const char *symbol;
788ed691b0SAlexander Potapenko };
798ed691b0SAlexander Potapenko 
808ed691b0SAlexander Potapenko /* Check observed report matches information in @r. */
report_matches(const struct expect_report * r)818ed691b0SAlexander Potapenko static bool report_matches(const struct expect_report *r)
828ed691b0SAlexander Potapenko {
838ed691b0SAlexander Potapenko 	typeof(observed.header) expected_header;
848ed691b0SAlexander Potapenko 	unsigned long flags;
858ed691b0SAlexander Potapenko 	bool ret = false;
868ed691b0SAlexander Potapenko 	const char *end;
878ed691b0SAlexander Potapenko 	char *cur;
888ed691b0SAlexander Potapenko 
898ed691b0SAlexander Potapenko 	/* Doubled-checked locking. */
908ed691b0SAlexander Potapenko 	if (!report_available() || !r->symbol)
918ed691b0SAlexander Potapenko 		return (!report_available() && !r->symbol);
928ed691b0SAlexander Potapenko 
938ed691b0SAlexander Potapenko 	/* Generate expected report contents. */
948ed691b0SAlexander Potapenko 
958ed691b0SAlexander Potapenko 	/* Title */
968ed691b0SAlexander Potapenko 	cur = expected_header;
978ed691b0SAlexander Potapenko 	end = &expected_header[sizeof(expected_header) - 1];
988ed691b0SAlexander Potapenko 
998ed691b0SAlexander Potapenko 	cur += scnprintf(cur, end - cur, "BUG: KMSAN: %s", r->error_type);
1008ed691b0SAlexander Potapenko 
1018ed691b0SAlexander Potapenko 	scnprintf(cur, end - cur, " in %s", r->symbol);
1028ed691b0SAlexander Potapenko 	/* The exact offset won't match, remove it; also strip module name. */
1038ed691b0SAlexander Potapenko 	cur = strchr(expected_header, '+');
1048ed691b0SAlexander Potapenko 	if (cur)
1058ed691b0SAlexander Potapenko 		*cur = '\0';
1068ed691b0SAlexander Potapenko 
1078ed691b0SAlexander Potapenko 	spin_lock_irqsave(&observed.lock, flags);
1088ed691b0SAlexander Potapenko 	if (!report_available())
1098ed691b0SAlexander Potapenko 		goto out; /* A new report is being captured. */
1108ed691b0SAlexander Potapenko 
1118ed691b0SAlexander Potapenko 	/* Finally match expected output to what we actually observed. */
1128ed691b0SAlexander Potapenko 	ret = strstr(observed.header, expected_header);
1138ed691b0SAlexander Potapenko out:
1148ed691b0SAlexander Potapenko 	spin_unlock_irqrestore(&observed.lock, flags);
1158ed691b0SAlexander Potapenko 
1168ed691b0SAlexander Potapenko 	return ret;
1178ed691b0SAlexander Potapenko }
1188ed691b0SAlexander Potapenko 
1198ed691b0SAlexander Potapenko /* ===== Test cases ===== */
1208ed691b0SAlexander Potapenko 
1218ed691b0SAlexander Potapenko /* Prevent replacing branch with select in LLVM. */
check_true(char * arg)1228ed691b0SAlexander Potapenko static noinline void check_true(char *arg)
1238ed691b0SAlexander Potapenko {
1248ed691b0SAlexander Potapenko 	pr_info("%s is true\n", arg);
1258ed691b0SAlexander Potapenko }
1268ed691b0SAlexander Potapenko 
check_false(char * arg)1278ed691b0SAlexander Potapenko static noinline void check_false(char *arg)
1288ed691b0SAlexander Potapenko {
1298ed691b0SAlexander Potapenko 	pr_info("%s is false\n", arg);
1308ed691b0SAlexander Potapenko }
1318ed691b0SAlexander Potapenko 
1328ed691b0SAlexander Potapenko #define USE(x)                           \
1338ed691b0SAlexander Potapenko 	do {                             \
1348ed691b0SAlexander Potapenko 		if (x)                   \
1358ed691b0SAlexander Potapenko 			check_true(#x);  \
1368ed691b0SAlexander Potapenko 		else                     \
1378ed691b0SAlexander Potapenko 			check_false(#x); \
1388ed691b0SAlexander Potapenko 	} while (0)
1398ed691b0SAlexander Potapenko 
1408ed691b0SAlexander Potapenko #define EXPECTATION_ETYPE_FN(e, reason, fn) \
1418ed691b0SAlexander Potapenko 	struct expect_report e = {          \
1428ed691b0SAlexander Potapenko 		.error_type = reason,       \
1438ed691b0SAlexander Potapenko 		.symbol = fn,               \
1448ed691b0SAlexander Potapenko 	}
1458ed691b0SAlexander Potapenko 
1468ed691b0SAlexander Potapenko #define EXPECTATION_NO_REPORT(e) EXPECTATION_ETYPE_FN(e, NULL, NULL)
1478ed691b0SAlexander Potapenko #define EXPECTATION_UNINIT_VALUE_FN(e, fn) \
1488ed691b0SAlexander Potapenko 	EXPECTATION_ETYPE_FN(e, "uninit-value", fn)
1498ed691b0SAlexander Potapenko #define EXPECTATION_UNINIT_VALUE(e) EXPECTATION_UNINIT_VALUE_FN(e, __func__)
1508ed691b0SAlexander Potapenko #define EXPECTATION_USE_AFTER_FREE(e) \
1518ed691b0SAlexander Potapenko 	EXPECTATION_ETYPE_FN(e, "use-after-free", __func__)
1528ed691b0SAlexander Potapenko 
1538ed691b0SAlexander Potapenko /* Test case: ensure that kmalloc() returns uninitialized memory. */
test_uninit_kmalloc(struct kunit * test)1548ed691b0SAlexander Potapenko static void test_uninit_kmalloc(struct kunit *test)
1558ed691b0SAlexander Potapenko {
1568ed691b0SAlexander Potapenko 	EXPECTATION_UNINIT_VALUE(expect);
1578ed691b0SAlexander Potapenko 	int *ptr;
1588ed691b0SAlexander Potapenko 
1598ed691b0SAlexander Potapenko 	kunit_info(test, "uninitialized kmalloc test (UMR report)\n");
1608ed691b0SAlexander Potapenko 	ptr = kmalloc(sizeof(*ptr), GFP_KERNEL);
1618ed691b0SAlexander Potapenko 	USE(*ptr);
1628ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
1638ed691b0SAlexander Potapenko }
1648ed691b0SAlexander Potapenko 
1658ed691b0SAlexander Potapenko /*
1668ed691b0SAlexander Potapenko  * Test case: ensure that kmalloc'ed memory becomes initialized after memset().
1678ed691b0SAlexander Potapenko  */
test_init_kmalloc(struct kunit * test)1688ed691b0SAlexander Potapenko static void test_init_kmalloc(struct kunit *test)
1698ed691b0SAlexander Potapenko {
1708ed691b0SAlexander Potapenko 	EXPECTATION_NO_REPORT(expect);
1718ed691b0SAlexander Potapenko 	int *ptr;
1728ed691b0SAlexander Potapenko 
1738ed691b0SAlexander Potapenko 	kunit_info(test, "initialized kmalloc test (no reports)\n");
1748ed691b0SAlexander Potapenko 	ptr = kmalloc(sizeof(*ptr), GFP_KERNEL);
1758ed691b0SAlexander Potapenko 	memset(ptr, 0, sizeof(*ptr));
1768ed691b0SAlexander Potapenko 	USE(*ptr);
1778ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
1788ed691b0SAlexander Potapenko }
1798ed691b0SAlexander Potapenko 
1808ed691b0SAlexander Potapenko /* Test case: ensure that kzalloc() returns initialized memory. */
test_init_kzalloc(struct kunit * test)1818ed691b0SAlexander Potapenko static void test_init_kzalloc(struct kunit *test)
1828ed691b0SAlexander Potapenko {
1838ed691b0SAlexander Potapenko 	EXPECTATION_NO_REPORT(expect);
1848ed691b0SAlexander Potapenko 	int *ptr;
1858ed691b0SAlexander Potapenko 
1868ed691b0SAlexander Potapenko 	kunit_info(test, "initialized kzalloc test (no reports)\n");
1878ed691b0SAlexander Potapenko 	ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
1888ed691b0SAlexander Potapenko 	USE(*ptr);
1898ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
1908ed691b0SAlexander Potapenko }
1918ed691b0SAlexander Potapenko 
1928ed691b0SAlexander Potapenko /* Test case: ensure that local variables are uninitialized by default. */
test_uninit_stack_var(struct kunit * test)1938ed691b0SAlexander Potapenko static void test_uninit_stack_var(struct kunit *test)
1948ed691b0SAlexander Potapenko {
1958ed691b0SAlexander Potapenko 	EXPECTATION_UNINIT_VALUE(expect);
1968ed691b0SAlexander Potapenko 	volatile int cond;
1978ed691b0SAlexander Potapenko 
1988ed691b0SAlexander Potapenko 	kunit_info(test, "uninitialized stack variable (UMR report)\n");
1998ed691b0SAlexander Potapenko 	USE(cond);
2008ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
2018ed691b0SAlexander Potapenko }
2028ed691b0SAlexander Potapenko 
2038ed691b0SAlexander Potapenko /* Test case: ensure that local variables with initializers are initialized. */
test_init_stack_var(struct kunit * test)2048ed691b0SAlexander Potapenko static void test_init_stack_var(struct kunit *test)
2058ed691b0SAlexander Potapenko {
2068ed691b0SAlexander Potapenko 	EXPECTATION_NO_REPORT(expect);
2078ed691b0SAlexander Potapenko 	volatile int cond = 1;
2088ed691b0SAlexander Potapenko 
2098ed691b0SAlexander Potapenko 	kunit_info(test, "initialized stack variable (no reports)\n");
2108ed691b0SAlexander Potapenko 	USE(cond);
2118ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
2128ed691b0SAlexander Potapenko }
2138ed691b0SAlexander Potapenko 
two_param_fn_2(int arg1,int arg2)2148ed691b0SAlexander Potapenko static noinline void two_param_fn_2(int arg1, int arg2)
2158ed691b0SAlexander Potapenko {
2168ed691b0SAlexander Potapenko 	USE(arg1);
2178ed691b0SAlexander Potapenko 	USE(arg2);
2188ed691b0SAlexander Potapenko }
2198ed691b0SAlexander Potapenko 
one_param_fn(int arg)2208ed691b0SAlexander Potapenko static noinline void one_param_fn(int arg)
2218ed691b0SAlexander Potapenko {
2228ed691b0SAlexander Potapenko 	two_param_fn_2(arg, arg);
2238ed691b0SAlexander Potapenko 	USE(arg);
2248ed691b0SAlexander Potapenko }
2258ed691b0SAlexander Potapenko 
two_param_fn(int arg1,int arg2)2268ed691b0SAlexander Potapenko static noinline void two_param_fn(int arg1, int arg2)
2278ed691b0SAlexander Potapenko {
2288ed691b0SAlexander Potapenko 	int init = 0;
2298ed691b0SAlexander Potapenko 
2308ed691b0SAlexander Potapenko 	one_param_fn(init);
2318ed691b0SAlexander Potapenko 	USE(arg1);
2328ed691b0SAlexander Potapenko 	USE(arg2);
2338ed691b0SAlexander Potapenko }
2348ed691b0SAlexander Potapenko 
test_params(struct kunit * test)2358ed691b0SAlexander Potapenko static void test_params(struct kunit *test)
2368ed691b0SAlexander Potapenko {
2378ed691b0SAlexander Potapenko #ifdef CONFIG_KMSAN_CHECK_PARAM_RETVAL
2388ed691b0SAlexander Potapenko 	/*
2398ed691b0SAlexander Potapenko 	 * With eager param/retval checking enabled, KMSAN will report an error
2408ed691b0SAlexander Potapenko 	 * before the call to two_param_fn().
2418ed691b0SAlexander Potapenko 	 */
2428ed691b0SAlexander Potapenko 	EXPECTATION_UNINIT_VALUE_FN(expect, "test_params");
2438ed691b0SAlexander Potapenko #else
2448ed691b0SAlexander Potapenko 	EXPECTATION_UNINIT_VALUE_FN(expect, "two_param_fn");
2458ed691b0SAlexander Potapenko #endif
2468ed691b0SAlexander Potapenko 	volatile int uninit, init = 1;
2478ed691b0SAlexander Potapenko 
2488ed691b0SAlexander Potapenko 	kunit_info(test,
2498ed691b0SAlexander Potapenko 		   "uninit passed through a function parameter (UMR report)\n");
2508ed691b0SAlexander Potapenko 	two_param_fn(uninit, init);
2518ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
2528ed691b0SAlexander Potapenko }
2538ed691b0SAlexander Potapenko 
signed_sum3(int a,int b,int c)2548ed691b0SAlexander Potapenko static int signed_sum3(int a, int b, int c)
2558ed691b0SAlexander Potapenko {
2568ed691b0SAlexander Potapenko 	return a + b + c;
2578ed691b0SAlexander Potapenko }
2588ed691b0SAlexander Potapenko 
2598ed691b0SAlexander Potapenko /*
2608ed691b0SAlexander Potapenko  * Test case: ensure that uninitialized values are tracked through function
2618ed691b0SAlexander Potapenko  * arguments.
2628ed691b0SAlexander Potapenko  */
test_uninit_multiple_params(struct kunit * test)2638ed691b0SAlexander Potapenko static void test_uninit_multiple_params(struct kunit *test)
2648ed691b0SAlexander Potapenko {
2658ed691b0SAlexander Potapenko 	EXPECTATION_UNINIT_VALUE(expect);
2668ed691b0SAlexander Potapenko 	volatile char b = 3, c;
2678ed691b0SAlexander Potapenko 	volatile int a;
2688ed691b0SAlexander Potapenko 
2698ed691b0SAlexander Potapenko 	kunit_info(test, "uninitialized local passed to fn (UMR report)\n");
2708ed691b0SAlexander Potapenko 	USE(signed_sum3(a, b, c));
2718ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
2728ed691b0SAlexander Potapenko }
2738ed691b0SAlexander Potapenko 
2748ed691b0SAlexander Potapenko /* Helper function to make an array uninitialized. */
do_uninit_local_array(char * array,int start,int stop)2758ed691b0SAlexander Potapenko static noinline void do_uninit_local_array(char *array, int start, int stop)
2768ed691b0SAlexander Potapenko {
2778ed691b0SAlexander Potapenko 	volatile char uninit;
2788ed691b0SAlexander Potapenko 
2798ed691b0SAlexander Potapenko 	for (int i = start; i < stop; i++)
2808ed691b0SAlexander Potapenko 		array[i] = uninit;
2818ed691b0SAlexander Potapenko }
2828ed691b0SAlexander Potapenko 
2838ed691b0SAlexander Potapenko /*
2848ed691b0SAlexander Potapenko  * Test case: ensure kmsan_check_memory() reports an error when checking
2858ed691b0SAlexander Potapenko  * uninitialized memory.
2868ed691b0SAlexander Potapenko  */
test_uninit_kmsan_check_memory(struct kunit * test)2878ed691b0SAlexander Potapenko static void test_uninit_kmsan_check_memory(struct kunit *test)
2888ed691b0SAlexander Potapenko {
2898ed691b0SAlexander Potapenko 	EXPECTATION_UNINIT_VALUE_FN(expect, "test_uninit_kmsan_check_memory");
2908ed691b0SAlexander Potapenko 	volatile char local_array[8];
2918ed691b0SAlexander Potapenko 
2928ed691b0SAlexander Potapenko 	kunit_info(
2938ed691b0SAlexander Potapenko 		test,
2948ed691b0SAlexander Potapenko 		"kmsan_check_memory() called on uninit local (UMR report)\n");
2958ed691b0SAlexander Potapenko 	do_uninit_local_array((char *)local_array, 5, 7);
2968ed691b0SAlexander Potapenko 
2978ed691b0SAlexander Potapenko 	kmsan_check_memory((char *)local_array, 8);
2988ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
2998ed691b0SAlexander Potapenko }
3008ed691b0SAlexander Potapenko 
3018ed691b0SAlexander Potapenko /*
3028ed691b0SAlexander Potapenko  * Test case: check that a virtual memory range created with vmap() from
3038ed691b0SAlexander Potapenko  * initialized pages is still considered as initialized.
3048ed691b0SAlexander Potapenko  */
test_init_kmsan_vmap_vunmap(struct kunit * test)3058ed691b0SAlexander Potapenko static void test_init_kmsan_vmap_vunmap(struct kunit *test)
3068ed691b0SAlexander Potapenko {
3078ed691b0SAlexander Potapenko 	EXPECTATION_NO_REPORT(expect);
3088ed691b0SAlexander Potapenko 	const int npages = 2;
3098ed691b0SAlexander Potapenko 	struct page **pages;
3108ed691b0SAlexander Potapenko 	void *vbuf;
3118ed691b0SAlexander Potapenko 
3128ed691b0SAlexander Potapenko 	kunit_info(test, "pages initialized via vmap (no reports)\n");
3138ed691b0SAlexander Potapenko 
3148ed691b0SAlexander Potapenko 	pages = kmalloc_array(npages, sizeof(*pages), GFP_KERNEL);
3158ed691b0SAlexander Potapenko 	for (int i = 0; i < npages; i++)
3168ed691b0SAlexander Potapenko 		pages[i] = alloc_page(GFP_KERNEL);
3178ed691b0SAlexander Potapenko 	vbuf = vmap(pages, npages, VM_MAP, PAGE_KERNEL);
3188ed691b0SAlexander Potapenko 	memset(vbuf, 0xfe, npages * PAGE_SIZE);
3198ed691b0SAlexander Potapenko 	for (int i = 0; i < npages; i++)
3208ed691b0SAlexander Potapenko 		kmsan_check_memory(page_address(pages[i]), PAGE_SIZE);
3218ed691b0SAlexander Potapenko 
3228ed691b0SAlexander Potapenko 	if (vbuf)
3238ed691b0SAlexander Potapenko 		vunmap(vbuf);
3248ed691b0SAlexander Potapenko 	for (int i = 0; i < npages; i++) {
3258ed691b0SAlexander Potapenko 		if (pages[i])
3268ed691b0SAlexander Potapenko 			__free_page(pages[i]);
3278ed691b0SAlexander Potapenko 	}
3288ed691b0SAlexander Potapenko 	kfree(pages);
3298ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
3308ed691b0SAlexander Potapenko }
3318ed691b0SAlexander Potapenko 
3328ed691b0SAlexander Potapenko /*
3338ed691b0SAlexander Potapenko  * Test case: ensure that memset() can initialize a buffer allocated via
3348ed691b0SAlexander Potapenko  * vmalloc().
3358ed691b0SAlexander Potapenko  */
test_init_vmalloc(struct kunit * test)3368ed691b0SAlexander Potapenko static void test_init_vmalloc(struct kunit *test)
3378ed691b0SAlexander Potapenko {
3388ed691b0SAlexander Potapenko 	EXPECTATION_NO_REPORT(expect);
3398ed691b0SAlexander Potapenko 	int npages = 8;
3408ed691b0SAlexander Potapenko 	char *buf;
3418ed691b0SAlexander Potapenko 
3428ed691b0SAlexander Potapenko 	kunit_info(test, "vmalloc buffer can be initialized (no reports)\n");
3438ed691b0SAlexander Potapenko 	buf = vmalloc(PAGE_SIZE * npages);
3448ed691b0SAlexander Potapenko 	buf[0] = 1;
3458ed691b0SAlexander Potapenko 	memset(buf, 0xfe, PAGE_SIZE * npages);
3468ed691b0SAlexander Potapenko 	USE(buf[0]);
3478ed691b0SAlexander Potapenko 	for (int i = 0; i < npages; i++)
3488ed691b0SAlexander Potapenko 		kmsan_check_memory(&buf[PAGE_SIZE * i], PAGE_SIZE);
3498ed691b0SAlexander Potapenko 	vfree(buf);
3508ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
3518ed691b0SAlexander Potapenko }
3528ed691b0SAlexander Potapenko 
3538ed691b0SAlexander Potapenko /* Test case: ensure that use-after-free reporting works. */
test_uaf(struct kunit * test)3548ed691b0SAlexander Potapenko static void test_uaf(struct kunit *test)
3558ed691b0SAlexander Potapenko {
3568ed691b0SAlexander Potapenko 	EXPECTATION_USE_AFTER_FREE(expect);
3578ed691b0SAlexander Potapenko 	volatile int value;
3588ed691b0SAlexander Potapenko 	volatile int *var;
3598ed691b0SAlexander Potapenko 
3608ed691b0SAlexander Potapenko 	kunit_info(test, "use-after-free in kmalloc-ed buffer (UMR report)\n");
3618ed691b0SAlexander Potapenko 	var = kmalloc(80, GFP_KERNEL);
3628ed691b0SAlexander Potapenko 	var[3] = 0xfeedface;
3638ed691b0SAlexander Potapenko 	kfree((int *)var);
3648ed691b0SAlexander Potapenko 	/* Copy the invalid value before checking it. */
3658ed691b0SAlexander Potapenko 	value = var[3];
3668ed691b0SAlexander Potapenko 	USE(value);
3678ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
3688ed691b0SAlexander Potapenko }
3698ed691b0SAlexander Potapenko 
3708ed691b0SAlexander Potapenko /*
3718ed691b0SAlexander Potapenko  * Test case: ensure that uninitialized values are propagated through per-CPU
3728ed691b0SAlexander Potapenko  * memory.
3738ed691b0SAlexander Potapenko  */
test_percpu_propagate(struct kunit * test)3748ed691b0SAlexander Potapenko static void test_percpu_propagate(struct kunit *test)
3758ed691b0SAlexander Potapenko {
3768ed691b0SAlexander Potapenko 	EXPECTATION_UNINIT_VALUE(expect);
3778ed691b0SAlexander Potapenko 	volatile int uninit, check;
3788ed691b0SAlexander Potapenko 
3798ed691b0SAlexander Potapenko 	kunit_info(test,
3808ed691b0SAlexander Potapenko 		   "uninit local stored to per_cpu memory (UMR report)\n");
3818ed691b0SAlexander Potapenko 
3828ed691b0SAlexander Potapenko 	this_cpu_write(per_cpu_var, uninit);
3838ed691b0SAlexander Potapenko 	check = this_cpu_read(per_cpu_var);
3848ed691b0SAlexander Potapenko 	USE(check);
3858ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
3868ed691b0SAlexander Potapenko }
3878ed691b0SAlexander Potapenko 
3888ed691b0SAlexander Potapenko /*
3898ed691b0SAlexander Potapenko  * Test case: ensure that passing uninitialized values to printk() leads to an
3908ed691b0SAlexander Potapenko  * error report.
3918ed691b0SAlexander Potapenko  */
test_printk(struct kunit * test)3928ed691b0SAlexander Potapenko static void test_printk(struct kunit *test)
3938ed691b0SAlexander Potapenko {
3948ed691b0SAlexander Potapenko #ifdef CONFIG_KMSAN_CHECK_PARAM_RETVAL
3958ed691b0SAlexander Potapenko 	/*
3968ed691b0SAlexander Potapenko 	 * With eager param/retval checking enabled, KMSAN will report an error
3978ed691b0SAlexander Potapenko 	 * before the call to pr_info().
3988ed691b0SAlexander Potapenko 	 */
3998ed691b0SAlexander Potapenko 	EXPECTATION_UNINIT_VALUE_FN(expect, "test_printk");
4008ed691b0SAlexander Potapenko #else
4018ed691b0SAlexander Potapenko 	EXPECTATION_UNINIT_VALUE_FN(expect, "number");
4028ed691b0SAlexander Potapenko #endif
4038ed691b0SAlexander Potapenko 	volatile int uninit;
4048ed691b0SAlexander Potapenko 
4058ed691b0SAlexander Potapenko 	kunit_info(test, "uninit local passed to pr_info() (UMR report)\n");
4068ed691b0SAlexander Potapenko 	pr_info("%px contains %d\n", &uninit, uninit);
4078ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
4088ed691b0SAlexander Potapenko }
4098ed691b0SAlexander Potapenko 
4108ed691b0SAlexander Potapenko /*
411d3402925SAlexander Potapenko  * Prevent the compiler from optimizing @var away. Without this, Clang may
412d3402925SAlexander Potapenko  * notice that @var is uninitialized and drop memcpy() calls that use it.
413d3402925SAlexander Potapenko  *
414d3402925SAlexander Potapenko  * There is OPTIMIZER_HIDE_VAR() in linux/compier.h that we cannot use here,
415d3402925SAlexander Potapenko  * because it is implemented as inline assembly receiving @var as a parameter
416d3402925SAlexander Potapenko  * and will enforce a KMSAN check. Same is true for e.g. barrier_data(var).
417d3402925SAlexander Potapenko  */
418d3402925SAlexander Potapenko #define DO_NOT_OPTIMIZE(var) barrier()
419d3402925SAlexander Potapenko 
420d3402925SAlexander Potapenko /*
421d3402925SAlexander Potapenko  * Test case: ensure that memcpy() correctly copies initialized values.
422d3402925SAlexander Potapenko  * Also serves as a regression test to ensure DO_NOT_OPTIMIZE() does not cause
423d3402925SAlexander Potapenko  * extra checks.
424d3402925SAlexander Potapenko  */
test_init_memcpy(struct kunit * test)425d3402925SAlexander Potapenko static void test_init_memcpy(struct kunit *test)
426d3402925SAlexander Potapenko {
427d3402925SAlexander Potapenko 	EXPECTATION_NO_REPORT(expect);
428d3402925SAlexander Potapenko 	volatile int src;
429d3402925SAlexander Potapenko 	volatile int dst = 0;
430d3402925SAlexander Potapenko 
431d3402925SAlexander Potapenko 	DO_NOT_OPTIMIZE(src);
432d3402925SAlexander Potapenko 	src = 1;
433d3402925SAlexander Potapenko 	kunit_info(
434d3402925SAlexander Potapenko 		test,
435d3402925SAlexander Potapenko 		"memcpy()ing aligned initialized src to aligned dst (no reports)\n");
436d3402925SAlexander Potapenko 	memcpy((void *)&dst, (void *)&src, sizeof(src));
437d3402925SAlexander Potapenko 	kmsan_check_memory((void *)&dst, sizeof(dst));
438d3402925SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
439d3402925SAlexander Potapenko }
440d3402925SAlexander Potapenko 
441d3402925SAlexander Potapenko /*
4428ed691b0SAlexander Potapenko  * Test case: ensure that memcpy() correctly copies uninitialized values between
4438ed691b0SAlexander Potapenko  * aligned `src` and `dst`.
4448ed691b0SAlexander Potapenko  */
test_memcpy_aligned_to_aligned(struct kunit * test)4458ed691b0SAlexander Potapenko static void test_memcpy_aligned_to_aligned(struct kunit *test)
4468ed691b0SAlexander Potapenko {
4478ed691b0SAlexander Potapenko 	EXPECTATION_UNINIT_VALUE_FN(expect, "test_memcpy_aligned_to_aligned");
4488ed691b0SAlexander Potapenko 	volatile int uninit_src;
4498ed691b0SAlexander Potapenko 	volatile int dst = 0;
4508ed691b0SAlexander Potapenko 
4518ed691b0SAlexander Potapenko 	kunit_info(
4528ed691b0SAlexander Potapenko 		test,
4538ed691b0SAlexander Potapenko 		"memcpy()ing aligned uninit src to aligned dst (UMR report)\n");
454d3402925SAlexander Potapenko 	DO_NOT_OPTIMIZE(uninit_src);
4558ed691b0SAlexander Potapenko 	memcpy((void *)&dst, (void *)&uninit_src, sizeof(uninit_src));
4568ed691b0SAlexander Potapenko 	kmsan_check_memory((void *)&dst, sizeof(dst));
4578ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
4588ed691b0SAlexander Potapenko }
4598ed691b0SAlexander Potapenko 
4608ed691b0SAlexander Potapenko /*
4618ed691b0SAlexander Potapenko  * Test case: ensure that memcpy() correctly copies uninitialized values between
4628ed691b0SAlexander Potapenko  * aligned `src` and unaligned `dst`.
4638ed691b0SAlexander Potapenko  *
4648ed691b0SAlexander Potapenko  * Copying aligned 4-byte value to an unaligned one leads to touching two
4658ed691b0SAlexander Potapenko  * aligned 4-byte values. This test case checks that KMSAN correctly reports an
4668ed691b0SAlexander Potapenko  * error on the first of the two values.
4678ed691b0SAlexander Potapenko  */
test_memcpy_aligned_to_unaligned(struct kunit * test)4688ed691b0SAlexander Potapenko static void test_memcpy_aligned_to_unaligned(struct kunit *test)
4698ed691b0SAlexander Potapenko {
4708ed691b0SAlexander Potapenko 	EXPECTATION_UNINIT_VALUE_FN(expect, "test_memcpy_aligned_to_unaligned");
4718ed691b0SAlexander Potapenko 	volatile int uninit_src;
4728ed691b0SAlexander Potapenko 	volatile char dst[8] = { 0 };
4738ed691b0SAlexander Potapenko 
4748ed691b0SAlexander Potapenko 	kunit_info(
4758ed691b0SAlexander Potapenko 		test,
4768ed691b0SAlexander Potapenko 		"memcpy()ing aligned uninit src to unaligned dst (UMR report)\n");
477d3402925SAlexander Potapenko 	DO_NOT_OPTIMIZE(uninit_src);
4788ed691b0SAlexander Potapenko 	memcpy((void *)&dst[1], (void *)&uninit_src, sizeof(uninit_src));
4798ed691b0SAlexander Potapenko 	kmsan_check_memory((void *)dst, 4);
4808ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
4818ed691b0SAlexander Potapenko }
4828ed691b0SAlexander Potapenko 
4838ed691b0SAlexander Potapenko /*
4848ed691b0SAlexander Potapenko  * Test case: ensure that memcpy() correctly copies uninitialized values between
4858ed691b0SAlexander Potapenko  * aligned `src` and unaligned `dst`.
4868ed691b0SAlexander Potapenko  *
4878ed691b0SAlexander Potapenko  * Copying aligned 4-byte value to an unaligned one leads to touching two
4888ed691b0SAlexander Potapenko  * aligned 4-byte values. This test case checks that KMSAN correctly reports an
4898ed691b0SAlexander Potapenko  * error on the second of the two values.
4908ed691b0SAlexander Potapenko  */
test_memcpy_aligned_to_unaligned2(struct kunit * test)4918ed691b0SAlexander Potapenko static void test_memcpy_aligned_to_unaligned2(struct kunit *test)
4928ed691b0SAlexander Potapenko {
4938ed691b0SAlexander Potapenko 	EXPECTATION_UNINIT_VALUE_FN(expect,
4948ed691b0SAlexander Potapenko 				    "test_memcpy_aligned_to_unaligned2");
4958ed691b0SAlexander Potapenko 	volatile int uninit_src;
4968ed691b0SAlexander Potapenko 	volatile char dst[8] = { 0 };
4978ed691b0SAlexander Potapenko 
4988ed691b0SAlexander Potapenko 	kunit_info(
4998ed691b0SAlexander Potapenko 		test,
5008ed691b0SAlexander Potapenko 		"memcpy()ing aligned uninit src to unaligned dst - part 2 (UMR report)\n");
501d3402925SAlexander Potapenko 	DO_NOT_OPTIMIZE(uninit_src);
5028ed691b0SAlexander Potapenko 	memcpy((void *)&dst[1], (void *)&uninit_src, sizeof(uninit_src));
5038ed691b0SAlexander Potapenko 	kmsan_check_memory((void *)&dst[4], sizeof(uninit_src));
5048ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
5058ed691b0SAlexander Potapenko }
5068ed691b0SAlexander Potapenko 
50778c74aeeSAlexander Potapenko /* Generate test cases for memset16(), memset32(), memset64(). */
50878c74aeeSAlexander Potapenko #define DEFINE_TEST_MEMSETXX(size)                                          \
50978c74aeeSAlexander Potapenko 	static void test_memset##size(struct kunit *test)                   \
51078c74aeeSAlexander Potapenko 	{                                                                   \
51178c74aeeSAlexander Potapenko 		EXPECTATION_NO_REPORT(expect);                              \
51278c74aeeSAlexander Potapenko 		volatile uint##size##_t uninit;                             \
51378c74aeeSAlexander Potapenko                                                                             \
51478c74aeeSAlexander Potapenko 		kunit_info(test,                                            \
51578c74aeeSAlexander Potapenko 			   "memset" #size "() should initialize memory\n"); \
51678c74aeeSAlexander Potapenko 		DO_NOT_OPTIMIZE(uninit);                                    \
51778c74aeeSAlexander Potapenko 		memset##size((uint##size##_t *)&uninit, 0, 1);              \
51878c74aeeSAlexander Potapenko 		kmsan_check_memory((void *)&uninit, sizeof(uninit));        \
51978c74aeeSAlexander Potapenko 		KUNIT_EXPECT_TRUE(test, report_matches(&expect));           \
52078c74aeeSAlexander Potapenko 	}
52178c74aeeSAlexander Potapenko 
52278c74aeeSAlexander Potapenko DEFINE_TEST_MEMSETXX(16)
52378c74aeeSAlexander Potapenko DEFINE_TEST_MEMSETXX(32)
52478c74aeeSAlexander Potapenko DEFINE_TEST_MEMSETXX(64)
52578c74aeeSAlexander Potapenko 
fibonacci(int * array,int size,int start)526d3402925SAlexander Potapenko static noinline void fibonacci(int *array, int size, int start)
527d3402925SAlexander Potapenko {
5288ed691b0SAlexander Potapenko 	if (start < 2 || (start == size))
5298ed691b0SAlexander Potapenko 		return;
5308ed691b0SAlexander Potapenko 	array[start] = array[start - 1] + array[start - 2];
5318ed691b0SAlexander Potapenko 	fibonacci(array, size, start + 1);
5328ed691b0SAlexander Potapenko }
5338ed691b0SAlexander Potapenko 
test_long_origin_chain(struct kunit * test)5348ed691b0SAlexander Potapenko static void test_long_origin_chain(struct kunit *test)
5358ed691b0SAlexander Potapenko {
536d3402925SAlexander Potapenko 	EXPECTATION_UNINIT_VALUE_FN(expect, "test_long_origin_chain");
5378ed691b0SAlexander Potapenko 	/* (KMSAN_MAX_ORIGIN_DEPTH * 2) recursive calls to fibonacci(). */
5388ed691b0SAlexander Potapenko 	volatile int accum[KMSAN_MAX_ORIGIN_DEPTH * 2 + 2];
5398ed691b0SAlexander Potapenko 	int last = ARRAY_SIZE(accum) - 1;
5408ed691b0SAlexander Potapenko 
5418ed691b0SAlexander Potapenko 	kunit_info(
5428ed691b0SAlexander Potapenko 		test,
5438ed691b0SAlexander Potapenko 		"origin chain exceeding KMSAN_MAX_ORIGIN_DEPTH (UMR report)\n");
5448ed691b0SAlexander Potapenko 	/*
5458ed691b0SAlexander Potapenko 	 * We do not set accum[1] to 0, so the uninitializedness will be carried
5468ed691b0SAlexander Potapenko 	 * over to accum[2..last].
5478ed691b0SAlexander Potapenko 	 */
5488ed691b0SAlexander Potapenko 	accum[0] = 1;
5498ed691b0SAlexander Potapenko 	fibonacci((int *)accum, ARRAY_SIZE(accum), 2);
5508ed691b0SAlexander Potapenko 	kmsan_check_memory((void *)&accum[last], sizeof(int));
5518ed691b0SAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
5528ed691b0SAlexander Potapenko }
5538ed691b0SAlexander Potapenko 
5546204c9abSAlexander Potapenko /*
5556204c9abSAlexander Potapenko  * Test case: ensure that saving/restoring/printing stacks to/from stackdepot
5566204c9abSAlexander Potapenko  * does not trigger errors.
5576204c9abSAlexander Potapenko  *
5586204c9abSAlexander Potapenko  * KMSAN uses stackdepot to store origin stack traces, that's why we do not
5596204c9abSAlexander Potapenko  * instrument lib/stackdepot.c. Yet it must properly mark its outputs as
5606204c9abSAlexander Potapenko  * initialized because other kernel features (e.g. netdev tracker) may also
5616204c9abSAlexander Potapenko  * access stackdepot from instrumented code.
5626204c9abSAlexander Potapenko  */
test_stackdepot_roundtrip(struct kunit * test)5636204c9abSAlexander Potapenko static void test_stackdepot_roundtrip(struct kunit *test)
5646204c9abSAlexander Potapenko {
5656204c9abSAlexander Potapenko 	unsigned long src_entries[16], *dst_entries;
5666204c9abSAlexander Potapenko 	unsigned int src_nentries, dst_nentries;
5676204c9abSAlexander Potapenko 	EXPECTATION_NO_REPORT(expect);
5686204c9abSAlexander Potapenko 	depot_stack_handle_t handle;
5696204c9abSAlexander Potapenko 
5706204c9abSAlexander Potapenko 	kunit_info(test, "testing stackdepot roundtrip (no reports)\n");
5716204c9abSAlexander Potapenko 
5726204c9abSAlexander Potapenko 	src_nentries =
5736204c9abSAlexander Potapenko 		stack_trace_save(src_entries, ARRAY_SIZE(src_entries), 1);
5746204c9abSAlexander Potapenko 	handle = stack_depot_save(src_entries, src_nentries, GFP_KERNEL);
5756204c9abSAlexander Potapenko 	stack_depot_print(handle);
5766204c9abSAlexander Potapenko 	dst_nentries = stack_depot_fetch(handle, &dst_entries);
5776204c9abSAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, src_nentries == dst_nentries);
5786204c9abSAlexander Potapenko 
5796204c9abSAlexander Potapenko 	kmsan_check_memory((void *)dst_entries,
5806204c9abSAlexander Potapenko 			   sizeof(*dst_entries) * dst_nentries);
5816204c9abSAlexander Potapenko 	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
5826204c9abSAlexander Potapenko }
5836204c9abSAlexander Potapenko 
5848ed691b0SAlexander Potapenko static struct kunit_case kmsan_test_cases[] = {
5858ed691b0SAlexander Potapenko 	KUNIT_CASE(test_uninit_kmalloc),
5868ed691b0SAlexander Potapenko 	KUNIT_CASE(test_init_kmalloc),
5878ed691b0SAlexander Potapenko 	KUNIT_CASE(test_init_kzalloc),
5888ed691b0SAlexander Potapenko 	KUNIT_CASE(test_uninit_stack_var),
5898ed691b0SAlexander Potapenko 	KUNIT_CASE(test_init_stack_var),
5908ed691b0SAlexander Potapenko 	KUNIT_CASE(test_params),
5918ed691b0SAlexander Potapenko 	KUNIT_CASE(test_uninit_multiple_params),
5928ed691b0SAlexander Potapenko 	KUNIT_CASE(test_uninit_kmsan_check_memory),
5938ed691b0SAlexander Potapenko 	KUNIT_CASE(test_init_kmsan_vmap_vunmap),
5948ed691b0SAlexander Potapenko 	KUNIT_CASE(test_init_vmalloc),
5958ed691b0SAlexander Potapenko 	KUNIT_CASE(test_uaf),
5968ed691b0SAlexander Potapenko 	KUNIT_CASE(test_percpu_propagate),
5978ed691b0SAlexander Potapenko 	KUNIT_CASE(test_printk),
598d3402925SAlexander Potapenko 	KUNIT_CASE(test_init_memcpy),
5998ed691b0SAlexander Potapenko 	KUNIT_CASE(test_memcpy_aligned_to_aligned),
6008ed691b0SAlexander Potapenko 	KUNIT_CASE(test_memcpy_aligned_to_unaligned),
6018ed691b0SAlexander Potapenko 	KUNIT_CASE(test_memcpy_aligned_to_unaligned2),
60278c74aeeSAlexander Potapenko 	KUNIT_CASE(test_memset16),
60378c74aeeSAlexander Potapenko 	KUNIT_CASE(test_memset32),
60478c74aeeSAlexander Potapenko 	KUNIT_CASE(test_memset64),
6058ed691b0SAlexander Potapenko 	KUNIT_CASE(test_long_origin_chain),
6066204c9abSAlexander Potapenko 	KUNIT_CASE(test_stackdepot_roundtrip),
6078ed691b0SAlexander Potapenko 	{},
6088ed691b0SAlexander Potapenko };
6098ed691b0SAlexander Potapenko 
6108ed691b0SAlexander Potapenko /* ===== End test cases ===== */
6118ed691b0SAlexander Potapenko 
test_init(struct kunit * test)6128ed691b0SAlexander Potapenko static int test_init(struct kunit *test)
6138ed691b0SAlexander Potapenko {
6148ed691b0SAlexander Potapenko 	unsigned long flags;
6158ed691b0SAlexander Potapenko 
6168ed691b0SAlexander Potapenko 	spin_lock_irqsave(&observed.lock, flags);
6178ed691b0SAlexander Potapenko 	observed.header[0] = '\0';
6188ed691b0SAlexander Potapenko 	observed.ignore = false;
6198ed691b0SAlexander Potapenko 	observed.available = false;
6208ed691b0SAlexander Potapenko 	spin_unlock_irqrestore(&observed.lock, flags);
6218ed691b0SAlexander Potapenko 
6228ed691b0SAlexander Potapenko 	return 0;
6238ed691b0SAlexander Potapenko }
6248ed691b0SAlexander Potapenko 
test_exit(struct kunit * test)6258ed691b0SAlexander Potapenko static void test_exit(struct kunit *test)
6268ed691b0SAlexander Potapenko {
6278ed691b0SAlexander Potapenko }
6288ed691b0SAlexander Potapenko 
kmsan_suite_init(struct kunit_suite * suite)6298ed691b0SAlexander Potapenko static int kmsan_suite_init(struct kunit_suite *suite)
6308ed691b0SAlexander Potapenko {
631*1f6ab566SPavankumar Kondeti 	register_trace_console(probe_console, NULL);
6328ed691b0SAlexander Potapenko 	return 0;
6338ed691b0SAlexander Potapenko }
6348ed691b0SAlexander Potapenko 
kmsan_suite_exit(struct kunit_suite * suite)6358ed691b0SAlexander Potapenko static void kmsan_suite_exit(struct kunit_suite *suite)
6368ed691b0SAlexander Potapenko {
637*1f6ab566SPavankumar Kondeti 	unregister_trace_console(probe_console, NULL);
6388ed691b0SAlexander Potapenko 	tracepoint_synchronize_unregister();
6398ed691b0SAlexander Potapenko }
6408ed691b0SAlexander Potapenko 
6418ed691b0SAlexander Potapenko static struct kunit_suite kmsan_test_suite = {
6428ed691b0SAlexander Potapenko 	.name = "kmsan",
6438ed691b0SAlexander Potapenko 	.test_cases = kmsan_test_cases,
6448ed691b0SAlexander Potapenko 	.init = test_init,
6458ed691b0SAlexander Potapenko 	.exit = test_exit,
6468ed691b0SAlexander Potapenko 	.suite_init = kmsan_suite_init,
6478ed691b0SAlexander Potapenko 	.suite_exit = kmsan_suite_exit,
6488ed691b0SAlexander Potapenko };
6498ed691b0SAlexander Potapenko kunit_test_suites(&kmsan_test_suite);
6508ed691b0SAlexander Potapenko 
6518ed691b0SAlexander Potapenko MODULE_LICENSE("GPL");
6528ed691b0SAlexander Potapenko MODULE_AUTHOR("Alexander Potapenko <glider@google.com>");
653