linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH mm 1/3] kasan: switch kunit tests to console tracepoints
@ 2022-09-24 18:31 andrey.konovalov
  2022-09-24 18:31 ` [PATCH mm 2/3] kasan: migrate kasan_rcu_uaf test to kunit andrey.konovalov
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: andrey.konovalov @ 2022-09-24 18:31 UTC (permalink / raw)
  To: Marco Elver, Alexander Potapenko
  Cc: Andrey Konovalov, Dmitry Vyukov, Andrey Ryabinin, kasan-dev,
	Andrew Morton, linux-mm, linux-kernel, Andrey Konovalov

From: Andrey Konovalov <andreyknvl@google.com>

Switch KUnit-compatible KASAN tests from using per-task KUnit resources
to console tracepoints.

This allows for two things:

1. Migrating tests that trigger a KASAN report in the context of a task
   other than current to KUnit framework.
   This is implemented in the patches that follow.

2. Parsing and matching the contents of KASAN reports.
   This is not yet implemented.

Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
 lib/Kconfig.kasan     |  2 +-
 mm/kasan/kasan_test.c | 85 +++++++++++++++++++++++++++++++------------
 mm/kasan/report.c     | 31 ----------------
 3 files changed, 63 insertions(+), 55 deletions(-)

diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan
index ca09b1cf8ee9..ba5b27962c34 100644
--- a/lib/Kconfig.kasan
+++ b/lib/Kconfig.kasan
@@ -181,7 +181,7 @@ config KASAN_VMALLOC
 
 config KASAN_KUNIT_TEST
 	tristate "KUnit-compatible tests of KASAN bug detection capabilities" if !KUNIT_ALL_TESTS
-	depends on KASAN && KUNIT
+	depends on KASAN && KUNIT && TRACEPOINTS
 	default KUNIT_ALL_TESTS
 	help
 	  A KUnit-based KASAN test suite. Triggers different kinds of
diff --git a/mm/kasan/kasan_test.c b/mm/kasan/kasan_test.c
index f25692def781..3a2886f85e69 100644
--- a/mm/kasan/kasan_test.c
+++ b/mm/kasan/kasan_test.c
@@ -5,8 +5,12 @@
  * Author: Andrey Ryabinin <a.ryabinin@samsung.com>
  */
 
+#define pr_fmt(fmt) "kasan_test: " fmt
+
+#include <kunit/test.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/kasan.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -14,21 +18,28 @@
 #include <linux/module.h>
 #include <linux/printk.h>
 #include <linux/random.h>
+#include <linux/set_memory.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/tracepoint.h>
 #include <linux/uaccess.h>
-#include <linux/io.h>
 #include <linux/vmalloc.h>
-#include <linux/set_memory.h>
+#include <trace/events/printk.h>
 
 #include <asm/page.h>
 
-#include <kunit/test.h>
-
 #include "kasan.h"
 
 #define OOB_TAG_OFF (IS_ENABLED(CONFIG_KASAN_GENERIC) ? 0 : KASAN_GRANULE_SIZE)
 
+static bool multishot;
+
+/* Fields set based on lines observed in the console. */
+static struct {
+	bool report_found;
+	bool async_fault;
+} test_status;
+
 /*
  * Some tests use these global variables to store return values from function
  * calls that could otherwise be eliminated by the compiler as dead code.
@@ -36,35 +47,61 @@
 void *kasan_ptr_result;
 int kasan_int_result;
 
-static struct kunit_resource resource;
-static struct kunit_kasan_status test_status;
-static bool multishot;
+/* Probe for console output: obtains test_status lines of interest. */
+static void probe_console(void *ignore, const char *buf, size_t len)
+{
+	if (strnstr(buf, "BUG: KASAN: ", len))
+		WRITE_ONCE(test_status.report_found, true);
+	else if (strnstr(buf, "Asynchronous fault: ", len))
+		WRITE_ONCE(test_status.async_fault, true);
+}
 
-/*
- * Temporarily enable multi-shot mode. Otherwise, KASAN would only report the
- * first detected bug and panic the kernel if panic_on_warn is enabled. For
- * hardware tag-based KASAN also allow tag checking to be reenabled for each
- * test, see the comment for KUNIT_EXPECT_KASAN_FAIL().
- */
-static int kasan_test_init(struct kunit *test)
+static void register_tracepoints(struct tracepoint *tp, void *ignore)
+{
+	check_trace_callback_type_console(probe_console);
+	if (!strcmp(tp->name, "console"))
+		WARN_ON(tracepoint_probe_register(tp, probe_console, NULL));
+}
+
+static void unregister_tracepoints(struct tracepoint *tp, void *ignore)
+{
+	if (!strcmp(tp->name, "console"))
+		tracepoint_probe_unregister(tp, probe_console, NULL);
+}
+
+static int kasan_suite_init(struct kunit_suite *suite)
 {
 	if (!kasan_enabled()) {
-		kunit_err(test, "can't run KASAN tests with KASAN disabled");
+		pr_err("Can't run KASAN tests with KASAN disabled");
 		return -1;
 	}
 
+	/*
+	 * Temporarily enable multi-shot mode. Otherwise, KASAN would only
+	 * report the first detected bug and panic the kernel if panic_on_warn
+	 * is enabled.
+	 */
 	multishot = kasan_save_enable_multi_shot();
-	test_status.report_found = false;
-	test_status.sync_fault = false;
-	kunit_add_named_resource(test, NULL, NULL, &resource,
-					"kasan_status", &test_status);
+
+	/*
+	 * Because we want to be able to build the test as a module, we need to
+	 * iterate through all known tracepoints, since the static registration
+	 * won't work here.
+	 */
+	for_each_kernel_tracepoint(register_tracepoints, NULL);
 	return 0;
 }
 
-static void kasan_test_exit(struct kunit *test)
+static void kasan_suite_exit(struct kunit_suite *suite)
 {
 	kasan_restore_multi_shot(multishot);
-	KUNIT_EXPECT_FALSE(test, test_status.report_found);
+	for_each_kernel_tracepoint(unregister_tracepoints, NULL);
+	tracepoint_synchronize_unregister();
+}
+
+static void kasan_test_exit(struct kunit *test)
+{
+	KUNIT_EXPECT_FALSE(test, READ_ONCE(test_status.report_found));
 }
 
 /**
@@ -106,11 +143,12 @@ static void kasan_test_exit(struct kunit *test)
 	if (IS_ENABLED(CONFIG_KASAN_HW_TAGS) &&				\
 	    kasan_sync_fault_possible()) {				\
 		if (READ_ONCE(test_status.report_found) &&		\
-		    READ_ONCE(test_status.sync_fault))			\
+		    !READ_ONCE(test_status.async_fault))		\
 			kasan_enable_tagging();				\
 		migrate_enable();					\
 	}								\
 	WRITE_ONCE(test_status.report_found, false);			\
+	WRITE_ONCE(test_status.async_fault, false);			\
 } while (0)
 
 #define KASAN_TEST_NEEDS_CONFIG_ON(test, config) do {			\
@@ -1440,9 +1478,10 @@ static struct kunit_case kasan_kunit_test_cases[] = {
 
 static struct kunit_suite kasan_kunit_test_suite = {
 	.name = "kasan",
-	.init = kasan_test_init,
 	.test_cases = kasan_kunit_test_cases,
 	.exit = kasan_test_exit,
+	.suite_init = kasan_suite_init,
+	.suite_exit = kasan_suite_exit,
 };
 
 kunit_test_suite(kasan_kunit_test_suite);
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index 39e8e5a80b82..f23d51a27414 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -30,8 +30,6 @@
 
 #include <asm/sections.h>
 
-#include <kunit/test.h>
-
 #include "kasan.h"
 #include "../slab.h"
 
@@ -114,41 +112,12 @@ EXPORT_SYMBOL_GPL(kasan_restore_multi_shot);
 
 #endif
 
-#if IS_ENABLED(CONFIG_KASAN_KUNIT_TEST)
-static void update_kunit_status(bool sync)
-{
-	struct kunit *test;
-	struct kunit_resource *resource;
-	struct kunit_kasan_status *status;
-
-	test = current->kunit_test;
-	if (!test)
-		return;
-
-	resource = kunit_find_named_resource(test, "kasan_status");
-	if (!resource) {
-		kunit_set_failure(test);
-		return;
-	}
-
-	status = (struct kunit_kasan_status *)resource->data;
-	WRITE_ONCE(status->report_found, true);
-	WRITE_ONCE(status->sync_fault, sync);
-
-	kunit_put_resource(resource);
-}
-#else
-static void update_kunit_status(bool sync) { }
-#endif
-
 static DEFINE_SPINLOCK(report_lock);
 
 static void start_report(unsigned long *flags, bool sync)
 {
 	/* Respect the /proc/sys/kernel/traceoff_on_warning interface. */
 	disable_trace_on_warning();
-	/* Update status of the currently running KASAN test. */
-	update_kunit_status(sync);
 	/* Do not allow LOCKDEP mangling KASAN reports. */
 	lockdep_off();
 	/* Make sure we don't end up in loop. */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH mm 2/3] kasan: migrate kasan_rcu_uaf test to kunit
  2022-09-24 18:31 [PATCH mm 1/3] kasan: switch kunit tests to console tracepoints andrey.konovalov
@ 2022-09-24 18:31 ` andrey.konovalov
  2022-09-27 13:16   ` Marco Elver
  2022-09-24 18:31 ` [PATCH mm 3/3] kasan: migrate workqueue_uaf " andrey.konovalov
  2022-09-27 13:13 ` [PATCH mm 1/3] kasan: switch kunit tests to console tracepoints Marco Elver
  2 siblings, 1 reply; 7+ messages in thread
From: andrey.konovalov @ 2022-09-24 18:31 UTC (permalink / raw)
  To: Marco Elver, Alexander Potapenko
  Cc: Andrey Konovalov, Dmitry Vyukov, Andrey Ryabinin, kasan-dev,
	Andrew Morton, linux-mm, linux-kernel, Andrey Konovalov

From: Andrey Konovalov <andreyknvl@google.com>

Migrate the kasan_rcu_uaf test to the KUnit framework.

Changes to the implementation of the test:

- Call rcu_barrier() after call_rcu() to make that the RCU callbacks get
  triggered before the test is over.

- Cast pointer passed to rcu_dereference_protected as __rcu to get rid of
  the Sparse warning.

- Check that KASAN prints a report via KUNIT_EXPECT_KASAN_FAIL.

Initially, this test was intended to check that Generic KASAN prints
auxiliary stack traces for RCU objects. Nevertheless, the test is enabled
for all modes to make that KASAN reports bad accesses in RCU callbacks.

The presence of auxiliary stack traces for the Generic mode needs to be
inspected manually.

Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
 mm/kasan/kasan_test.c        | 37 ++++++++++++++++++++++++++++++++++++
 mm/kasan/kasan_test_module.c | 30 -----------------------------
 2 files changed, 37 insertions(+), 30 deletions(-)

diff --git a/mm/kasan/kasan_test.c b/mm/kasan/kasan_test.c
index 3a2886f85e69..005776325e20 100644
--- a/mm/kasan/kasan_test.c
+++ b/mm/kasan/kasan_test.c
@@ -1134,6 +1134,42 @@ static void kmalloc_double_kzfree(struct kunit *test)
 	KUNIT_EXPECT_KASAN_FAIL(test, kfree_sensitive(ptr));
 }
 
+static struct kasan_rcu_info {
+	int i;
+	struct rcu_head rcu;
+} *global_rcu_ptr;
+
+static void rcu_uaf_reclaim(struct rcu_head *rp)
+{
+	struct kasan_rcu_info *fp =
+		container_of(rp, struct kasan_rcu_info, rcu);
+
+	kfree(fp);
+	((volatile struct kasan_rcu_info *)fp)->i;
+}
+
+/*
+ * Check that Generic KASAN prints auxiliary stack traces for RCU callbacks.
+ * The report needs to be inspected manually.
+ *
+ * This test is still enabled for other KASAN modes to make sure that all modes
+ * report bad accesses in tested scenarios.
+ */
+static void rcu_uaf(struct kunit *test)
+{
+	struct kasan_rcu_info *ptr;
+
+	ptr = kmalloc(sizeof(struct kasan_rcu_info), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
+
+	global_rcu_ptr = rcu_dereference_protected(
+				(struct kasan_rcu_info __rcu *)ptr, NULL);
+
+	KUNIT_EXPECT_KASAN_FAIL(test,
+		call_rcu(&global_rcu_ptr->rcu, rcu_uaf_reclaim);
+		rcu_barrier());
+}
+
 static void vmalloc_helpers_tags(struct kunit *test)
 {
 	void *ptr;
@@ -1465,6 +1501,7 @@ static struct kunit_case kasan_kunit_test_cases[] = {
 	KUNIT_CASE(kasan_bitops_generic),
 	KUNIT_CASE(kasan_bitops_tags),
 	KUNIT_CASE(kmalloc_double_kzfree),
+	KUNIT_CASE(rcu_uaf),
 	KUNIT_CASE(vmalloc_helpers_tags),
 	KUNIT_CASE(vmalloc_oob),
 	KUNIT_CASE(vmap_tags),
diff --git a/mm/kasan/kasan_test_module.c b/mm/kasan/kasan_test_module.c
index e4ca82dc2c16..4688cbcd722d 100644
--- a/mm/kasan/kasan_test_module.c
+++ b/mm/kasan/kasan_test_module.c
@@ -62,35 +62,6 @@ static noinline void __init copy_user_test(void)
 	kfree(kmem);
 }
 
-static struct kasan_rcu_info {
-	int i;
-	struct rcu_head rcu;
-} *global_rcu_ptr;
-
-static noinline void __init kasan_rcu_reclaim(struct rcu_head *rp)
-{
-	struct kasan_rcu_info *fp = container_of(rp,
-						struct kasan_rcu_info, rcu);
-
-	kfree(fp);
-	((volatile struct kasan_rcu_info *)fp)->i;
-}
-
-static noinline void __init kasan_rcu_uaf(void)
-{
-	struct kasan_rcu_info *ptr;
-
-	pr_info("use-after-free in kasan_rcu_reclaim\n");
-	ptr = kmalloc(sizeof(struct kasan_rcu_info), GFP_KERNEL);
-	if (!ptr) {
-		pr_err("Allocation failed\n");
-		return;
-	}
-
-	global_rcu_ptr = rcu_dereference_protected(ptr, NULL);
-	call_rcu(&global_rcu_ptr->rcu, kasan_rcu_reclaim);
-}
-
 static noinline void __init kasan_workqueue_work(struct work_struct *work)
 {
 	kfree(work);
@@ -130,7 +101,6 @@ static int __init test_kasan_module_init(void)
 	bool multishot = kasan_save_enable_multi_shot();
 
 	copy_user_test();
-	kasan_rcu_uaf();
 	kasan_workqueue_uaf();
 
 	kasan_restore_multi_shot(multishot);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH mm 3/3] kasan: migrate workqueue_uaf test to kunit
  2022-09-24 18:31 [PATCH mm 1/3] kasan: switch kunit tests to console tracepoints andrey.konovalov
  2022-09-24 18:31 ` [PATCH mm 2/3] kasan: migrate kasan_rcu_uaf test to kunit andrey.konovalov
@ 2022-09-24 18:31 ` andrey.konovalov
  2022-09-27 13:17   ` Marco Elver
  2022-09-27 13:13 ` [PATCH mm 1/3] kasan: switch kunit tests to console tracepoints Marco Elver
  2 siblings, 1 reply; 7+ messages in thread
From: andrey.konovalov @ 2022-09-24 18:31 UTC (permalink / raw)
  To: Marco Elver, Alexander Potapenko
  Cc: Andrey Konovalov, Dmitry Vyukov, Andrey Ryabinin, kasan-dev,
	Andrew Morton, linux-mm, linux-kernel, Andrey Konovalov

From: Andrey Konovalov <andreyknvl@google.com>

Migrate the workqueue_uaf test to the KUnit framework.

Initially, this test was intended to check that Generic KASAN prints
auxiliary stack traces for workqueues. Nevertheless, the test is enabled
for all modes to make that KASAN reports bad accesses in the tested
scenario.

The presence of auxiliary stack traces for the Generic mode needs to be
inspected manually.

Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
---
 mm/kasan/kasan_test.c        | 40 +++++++++++++++++++++++++++++-------
 mm/kasan/kasan_test_module.c | 30 ---------------------------
 2 files changed, 33 insertions(+), 37 deletions(-)

diff --git a/mm/kasan/kasan_test.c b/mm/kasan/kasan_test.c
index 005776325e20..71cb402c404f 100644
--- a/mm/kasan/kasan_test.c
+++ b/mm/kasan/kasan_test.c
@@ -1134,6 +1134,14 @@ static void kmalloc_double_kzfree(struct kunit *test)
 	KUNIT_EXPECT_KASAN_FAIL(test, kfree_sensitive(ptr));
 }
 
+/*
+ * The two tests below check that Generic KASAN prints auxiliary stack traces
+ * for RCU callbacks and workqueues. The reports need to be inspected manually.
+ *
+ * These tests are still enabled for other KASAN modes to make sure that all
+ * modes report bad accesses in tested scenarios.
+ */
+
 static struct kasan_rcu_info {
 	int i;
 	struct rcu_head rcu;
@@ -1148,13 +1156,6 @@ static void rcu_uaf_reclaim(struct rcu_head *rp)
 	((volatile struct kasan_rcu_info *)fp)->i;
 }
 
-/*
- * Check that Generic KASAN prints auxiliary stack traces for RCU callbacks.
- * The report needs to be inspected manually.
- *
- * This test is still enabled for other KASAN modes to make sure that all modes
- * report bad accesses in tested scenarios.
- */
 static void rcu_uaf(struct kunit *test)
 {
 	struct kasan_rcu_info *ptr;
@@ -1170,6 +1171,30 @@ static void rcu_uaf(struct kunit *test)
 		rcu_barrier());
 }
 
+static void workqueue_uaf_work(struct work_struct *work)
+{
+	kfree(work);
+}
+
+static void workqueue_uaf(struct kunit *test)
+{
+	struct workqueue_struct *workqueue;
+	struct work_struct *work;
+
+	workqueue = create_workqueue("kasan_workqueue_test");
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, workqueue);
+
+	work = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, work);
+
+	INIT_WORK(work, workqueue_uaf_work);
+	queue_work(workqueue, work);
+	destroy_workqueue(workqueue);
+
+	KUNIT_EXPECT_KASAN_FAIL(test,
+		((volatile struct work_struct *)work)->data);
+}
+
 static void vmalloc_helpers_tags(struct kunit *test)
 {
 	void *ptr;
@@ -1502,6 +1527,7 @@ static struct kunit_case kasan_kunit_test_cases[] = {
 	KUNIT_CASE(kasan_bitops_tags),
 	KUNIT_CASE(kmalloc_double_kzfree),
 	KUNIT_CASE(rcu_uaf),
+	KUNIT_CASE(workqueue_uaf),
 	KUNIT_CASE(vmalloc_helpers_tags),
 	KUNIT_CASE(vmalloc_oob),
 	KUNIT_CASE(vmap_tags),
diff --git a/mm/kasan/kasan_test_module.c b/mm/kasan/kasan_test_module.c
index 4688cbcd722d..7be7bed456ef 100644
--- a/mm/kasan/kasan_test_module.c
+++ b/mm/kasan/kasan_test_module.c
@@ -62,35 +62,6 @@ static noinline void __init copy_user_test(void)
 	kfree(kmem);
 }
 
-static noinline void __init kasan_workqueue_work(struct work_struct *work)
-{
-	kfree(work);
-}
-
-static noinline void __init kasan_workqueue_uaf(void)
-{
-	struct workqueue_struct *workqueue;
-	struct work_struct *work;
-
-	workqueue = create_workqueue("kasan_wq_test");
-	if (!workqueue) {
-		pr_err("Allocation failed\n");
-		return;
-	}
-	work = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
-	if (!work) {
-		pr_err("Allocation failed\n");
-		return;
-	}
-
-	INIT_WORK(work, kasan_workqueue_work);
-	queue_work(workqueue, work);
-	destroy_workqueue(workqueue);
-
-	pr_info("use-after-free on workqueue\n");
-	((volatile struct work_struct *)work)->data;
-}
-
 static int __init test_kasan_module_init(void)
 {
 	/*
@@ -101,7 +72,6 @@ static int __init test_kasan_module_init(void)
 	bool multishot = kasan_save_enable_multi_shot();
 
 	copy_user_test();
-	kasan_workqueue_uaf();
 
 	kasan_restore_multi_shot(multishot);
 	return -EAGAIN;
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH mm 1/3] kasan: switch kunit tests to console tracepoints
  2022-09-24 18:31 [PATCH mm 1/3] kasan: switch kunit tests to console tracepoints andrey.konovalov
  2022-09-24 18:31 ` [PATCH mm 2/3] kasan: migrate kasan_rcu_uaf test to kunit andrey.konovalov
  2022-09-24 18:31 ` [PATCH mm 3/3] kasan: migrate workqueue_uaf " andrey.konovalov
@ 2022-09-27 13:13 ` Marco Elver
  2022-09-27 17:09   ` Andrey Konovalov
  2 siblings, 1 reply; 7+ messages in thread
From: Marco Elver @ 2022-09-27 13:13 UTC (permalink / raw)
  To: andrey.konovalov
  Cc: Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Andrey Ryabinin, kasan-dev, Andrew Morton, linux-mm,
	linux-kernel, Andrey Konovalov

On Sat, Sep 24, 2022 at 08:31PM +0200, andrey.konovalov@linux.dev wrote:
> From: Andrey Konovalov <andreyknvl@google.com>
> 
> Switch KUnit-compatible KASAN tests from using per-task KUnit resources
> to console tracepoints.
> 
> This allows for two things:
> 
> 1. Migrating tests that trigger a KASAN report in the context of a task
>    other than current to KUnit framework.
>    This is implemented in the patches that follow.
> 
> 2. Parsing and matching the contents of KASAN reports.
>    This is not yet implemented.
> 
> Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
> ---
>  lib/Kconfig.kasan     |  2 +-
>  mm/kasan/kasan_test.c | 85 +++++++++++++++++++++++++++++++------------
>  mm/kasan/report.c     | 31 ----------------
>  3 files changed, 63 insertions(+), 55 deletions(-)
> 
> diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan
> index ca09b1cf8ee9..ba5b27962c34 100644
> --- a/lib/Kconfig.kasan
> +++ b/lib/Kconfig.kasan
> @@ -181,7 +181,7 @@ config KASAN_VMALLOC
>  
>  config KASAN_KUNIT_TEST
>  	tristate "KUnit-compatible tests of KASAN bug detection capabilities" if !KUNIT_ALL_TESTS
> -	depends on KASAN && KUNIT
> +	depends on KASAN && KUNIT && TRACEPOINTS
>  	default KUNIT_ALL_TESTS
>  	help
>  	  A KUnit-based KASAN test suite. Triggers different kinds of
> diff --git a/mm/kasan/kasan_test.c b/mm/kasan/kasan_test.c
> index f25692def781..3a2886f85e69 100644
> --- a/mm/kasan/kasan_test.c
> +++ b/mm/kasan/kasan_test.c
> @@ -5,8 +5,12 @@
>   * Author: Andrey Ryabinin <a.ryabinin@samsung.com>
>   */
>  
> +#define pr_fmt(fmt) "kasan_test: " fmt
> +
> +#include <kunit/test.h>
>  #include <linux/bitops.h>
>  #include <linux/delay.h>
> +#include <linux/io.h>
>  #include <linux/kasan.h>
>  #include <linux/kernel.h>
>  #include <linux/mm.h>
> @@ -14,21 +18,28 @@
>  #include <linux/module.h>
>  #include <linux/printk.h>
>  #include <linux/random.h>
> +#include <linux/set_memory.h>
>  #include <linux/slab.h>
>  #include <linux/string.h>
> +#include <linux/tracepoint.h>
>  #include <linux/uaccess.h>
> -#include <linux/io.h>
>  #include <linux/vmalloc.h>
> -#include <linux/set_memory.h>
> +#include <trace/events/printk.h>
>  
>  #include <asm/page.h>
>  
> -#include <kunit/test.h>
> -
>  #include "kasan.h"
>  
>  #define OOB_TAG_OFF (IS_ENABLED(CONFIG_KASAN_GENERIC) ? 0 : KASAN_GRANULE_SIZE)
>  
> +static bool multishot;
> +
> +/* Fields set based on lines observed in the console. */
> +static struct {
> +	bool report_found;
> +	bool async_fault;
> +} test_status;
> +
>  /*
>   * Some tests use these global variables to store return values from function
>   * calls that could otherwise be eliminated by the compiler as dead code.
> @@ -36,35 +47,61 @@
>  void *kasan_ptr_result;
>  int kasan_int_result;
>  
> -static struct kunit_resource resource;
> -static struct kunit_kasan_status test_status;

Also remove this struct from kasan.h?


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH mm 2/3] kasan: migrate kasan_rcu_uaf test to kunit
  2022-09-24 18:31 ` [PATCH mm 2/3] kasan: migrate kasan_rcu_uaf test to kunit andrey.konovalov
@ 2022-09-27 13:16   ` Marco Elver
  0 siblings, 0 replies; 7+ messages in thread
From: Marco Elver @ 2022-09-27 13:16 UTC (permalink / raw)
  To: andrey.konovalov
  Cc: Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Andrey Ryabinin, kasan-dev, Andrew Morton, linux-mm,
	linux-kernel, Andrey Konovalov

On Sat, Sep 24, 2022 at 08:31PM +0200, andrey.konovalov@linux.dev wrote:
> From: Andrey Konovalov <andreyknvl@google.com>
> 
> Migrate the kasan_rcu_uaf test to the KUnit framework.
> 
> Changes to the implementation of the test:
> 
> - Call rcu_barrier() after call_rcu() to make that the RCU callbacks get
>   triggered before the test is over.
> 
> - Cast pointer passed to rcu_dereference_protected as __rcu to get rid of
>   the Sparse warning.
> 
> - Check that KASAN prints a report via KUNIT_EXPECT_KASAN_FAIL.
> 
> Initially, this test was intended to check that Generic KASAN prints
> auxiliary stack traces for RCU objects. Nevertheless, the test is enabled
> for all modes to make that KASAN reports bad accesses in RCU callbacks.
> 
> The presence of auxiliary stack traces for the Generic mode needs to be
> inspected manually.
> 
> Signed-off-by: Andrey Konovalov <andreyknvl@google.com>

Reviewed-by: Marco Elver <elver@google.com>

> ---
>  mm/kasan/kasan_test.c        | 37 ++++++++++++++++++++++++++++++++++++
>  mm/kasan/kasan_test_module.c | 30 -----------------------------
>  2 files changed, 37 insertions(+), 30 deletions(-)
> 
> diff --git a/mm/kasan/kasan_test.c b/mm/kasan/kasan_test.c
> index 3a2886f85e69..005776325e20 100644
> --- a/mm/kasan/kasan_test.c
> +++ b/mm/kasan/kasan_test.c
> @@ -1134,6 +1134,42 @@ static void kmalloc_double_kzfree(struct kunit *test)
>  	KUNIT_EXPECT_KASAN_FAIL(test, kfree_sensitive(ptr));
>  }
>  
> +static struct kasan_rcu_info {
> +	int i;
> +	struct rcu_head rcu;
> +} *global_rcu_ptr;
> +
> +static void rcu_uaf_reclaim(struct rcu_head *rp)
> +{
> +	struct kasan_rcu_info *fp =
> +		container_of(rp, struct kasan_rcu_info, rcu);
> +
> +	kfree(fp);
> +	((volatile struct kasan_rcu_info *)fp)->i;
> +}
> +
> +/*
> + * Check that Generic KASAN prints auxiliary stack traces for RCU callbacks.
> + * The report needs to be inspected manually.
> + *
> + * This test is still enabled for other KASAN modes to make sure that all modes
> + * report bad accesses in tested scenarios.
> + */
> +static void rcu_uaf(struct kunit *test)
> +{
> +	struct kasan_rcu_info *ptr;
> +
> +	ptr = kmalloc(sizeof(struct kasan_rcu_info), GFP_KERNEL);
> +	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
> +
> +	global_rcu_ptr = rcu_dereference_protected(
> +				(struct kasan_rcu_info __rcu *)ptr, NULL);
> +
> +	KUNIT_EXPECT_KASAN_FAIL(test,
> +		call_rcu(&global_rcu_ptr->rcu, rcu_uaf_reclaim);
> +		rcu_barrier());
> +}
> +
>  static void vmalloc_helpers_tags(struct kunit *test)
>  {
>  	void *ptr;
> @@ -1465,6 +1501,7 @@ static struct kunit_case kasan_kunit_test_cases[] = {
>  	KUNIT_CASE(kasan_bitops_generic),
>  	KUNIT_CASE(kasan_bitops_tags),
>  	KUNIT_CASE(kmalloc_double_kzfree),
> +	KUNIT_CASE(rcu_uaf),
>  	KUNIT_CASE(vmalloc_helpers_tags),
>  	KUNIT_CASE(vmalloc_oob),
>  	KUNIT_CASE(vmap_tags),
> diff --git a/mm/kasan/kasan_test_module.c b/mm/kasan/kasan_test_module.c
> index e4ca82dc2c16..4688cbcd722d 100644
> --- a/mm/kasan/kasan_test_module.c
> +++ b/mm/kasan/kasan_test_module.c
> @@ -62,35 +62,6 @@ static noinline void __init copy_user_test(void)
>  	kfree(kmem);
>  }
>  
> -static struct kasan_rcu_info {
> -	int i;
> -	struct rcu_head rcu;
> -} *global_rcu_ptr;
> -
> -static noinline void __init kasan_rcu_reclaim(struct rcu_head *rp)
> -{
> -	struct kasan_rcu_info *fp = container_of(rp,
> -						struct kasan_rcu_info, rcu);
> -
> -	kfree(fp);
> -	((volatile struct kasan_rcu_info *)fp)->i;
> -}
> -
> -static noinline void __init kasan_rcu_uaf(void)
> -{
> -	struct kasan_rcu_info *ptr;
> -
> -	pr_info("use-after-free in kasan_rcu_reclaim\n");
> -	ptr = kmalloc(sizeof(struct kasan_rcu_info), GFP_KERNEL);
> -	if (!ptr) {
> -		pr_err("Allocation failed\n");
> -		return;
> -	}
> -
> -	global_rcu_ptr = rcu_dereference_protected(ptr, NULL);
> -	call_rcu(&global_rcu_ptr->rcu, kasan_rcu_reclaim);
> -}
> -
>  static noinline void __init kasan_workqueue_work(struct work_struct *work)
>  {
>  	kfree(work);
> @@ -130,7 +101,6 @@ static int __init test_kasan_module_init(void)
>  	bool multishot = kasan_save_enable_multi_shot();
>  
>  	copy_user_test();
> -	kasan_rcu_uaf();
>  	kasan_workqueue_uaf();
>  
>  	kasan_restore_multi_shot(multishot);
> -- 
> 2.25.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH mm 3/3] kasan: migrate workqueue_uaf test to kunit
  2022-09-24 18:31 ` [PATCH mm 3/3] kasan: migrate workqueue_uaf " andrey.konovalov
@ 2022-09-27 13:17   ` Marco Elver
  0 siblings, 0 replies; 7+ messages in thread
From: Marco Elver @ 2022-09-27 13:17 UTC (permalink / raw)
  To: andrey.konovalov
  Cc: Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
	Andrey Ryabinin, kasan-dev, Andrew Morton, linux-mm,
	linux-kernel, Andrey Konovalov

On Sat, Sep 24, 2022 at 08:31PM +0200, andrey.konovalov@linux.dev wrote:
> From: Andrey Konovalov <andreyknvl@google.com>
> 
> Migrate the workqueue_uaf test to the KUnit framework.
> 
> Initially, this test was intended to check that Generic KASAN prints
> auxiliary stack traces for workqueues. Nevertheless, the test is enabled
> for all modes to make that KASAN reports bad accesses in the tested
> scenario.
> 
> The presence of auxiliary stack traces for the Generic mode needs to be
> inspected manually.
> 
> Signed-off-by: Andrey Konovalov <andreyknvl@google.com>

Reviewed-by: Marco Elver <elver@google.com>

> ---
>  mm/kasan/kasan_test.c        | 40 +++++++++++++++++++++++++++++-------
>  mm/kasan/kasan_test_module.c | 30 ---------------------------
>  2 files changed, 33 insertions(+), 37 deletions(-)
> 
> diff --git a/mm/kasan/kasan_test.c b/mm/kasan/kasan_test.c
> index 005776325e20..71cb402c404f 100644
> --- a/mm/kasan/kasan_test.c
> +++ b/mm/kasan/kasan_test.c
> @@ -1134,6 +1134,14 @@ static void kmalloc_double_kzfree(struct kunit *test)
>  	KUNIT_EXPECT_KASAN_FAIL(test, kfree_sensitive(ptr));
>  }
>  
> +/*
> + * The two tests below check that Generic KASAN prints auxiliary stack traces
> + * for RCU callbacks and workqueues. The reports need to be inspected manually.
> + *
> + * These tests are still enabled for other KASAN modes to make sure that all
> + * modes report bad accesses in tested scenarios.
> + */
> +
>  static struct kasan_rcu_info {
>  	int i;
>  	struct rcu_head rcu;
> @@ -1148,13 +1156,6 @@ static void rcu_uaf_reclaim(struct rcu_head *rp)
>  	((volatile struct kasan_rcu_info *)fp)->i;
>  }
>  
> -/*
> - * Check that Generic KASAN prints auxiliary stack traces for RCU callbacks.
> - * The report needs to be inspected manually.
> - *
> - * This test is still enabled for other KASAN modes to make sure that all modes
> - * report bad accesses in tested scenarios.
> - */
>  static void rcu_uaf(struct kunit *test)
>  {
>  	struct kasan_rcu_info *ptr;
> @@ -1170,6 +1171,30 @@ static void rcu_uaf(struct kunit *test)
>  		rcu_barrier());
>  }
>  
> +static void workqueue_uaf_work(struct work_struct *work)
> +{
> +	kfree(work);
> +}
> +
> +static void workqueue_uaf(struct kunit *test)
> +{
> +	struct workqueue_struct *workqueue;
> +	struct work_struct *work;
> +
> +	workqueue = create_workqueue("kasan_workqueue_test");
> +	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, workqueue);
> +
> +	work = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
> +	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, work);
> +
> +	INIT_WORK(work, workqueue_uaf_work);
> +	queue_work(workqueue, work);
> +	destroy_workqueue(workqueue);
> +
> +	KUNIT_EXPECT_KASAN_FAIL(test,
> +		((volatile struct work_struct *)work)->data);
> +}
> +
>  static void vmalloc_helpers_tags(struct kunit *test)
>  {
>  	void *ptr;
> @@ -1502,6 +1527,7 @@ static struct kunit_case kasan_kunit_test_cases[] = {
>  	KUNIT_CASE(kasan_bitops_tags),
>  	KUNIT_CASE(kmalloc_double_kzfree),
>  	KUNIT_CASE(rcu_uaf),
> +	KUNIT_CASE(workqueue_uaf),
>  	KUNIT_CASE(vmalloc_helpers_tags),
>  	KUNIT_CASE(vmalloc_oob),
>  	KUNIT_CASE(vmap_tags),
> diff --git a/mm/kasan/kasan_test_module.c b/mm/kasan/kasan_test_module.c
> index 4688cbcd722d..7be7bed456ef 100644
> --- a/mm/kasan/kasan_test_module.c
> +++ b/mm/kasan/kasan_test_module.c
> @@ -62,35 +62,6 @@ static noinline void __init copy_user_test(void)
>  	kfree(kmem);
>  }
>  
> -static noinline void __init kasan_workqueue_work(struct work_struct *work)
> -{
> -	kfree(work);
> -}
> -
> -static noinline void __init kasan_workqueue_uaf(void)
> -{
> -	struct workqueue_struct *workqueue;
> -	struct work_struct *work;
> -
> -	workqueue = create_workqueue("kasan_wq_test");
> -	if (!workqueue) {
> -		pr_err("Allocation failed\n");
> -		return;
> -	}
> -	work = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
> -	if (!work) {
> -		pr_err("Allocation failed\n");
> -		return;
> -	}
> -
> -	INIT_WORK(work, kasan_workqueue_work);
> -	queue_work(workqueue, work);
> -	destroy_workqueue(workqueue);
> -
> -	pr_info("use-after-free on workqueue\n");
> -	((volatile struct work_struct *)work)->data;
> -}
> -
>  static int __init test_kasan_module_init(void)
>  {
>  	/*
> @@ -101,7 +72,6 @@ static int __init test_kasan_module_init(void)
>  	bool multishot = kasan_save_enable_multi_shot();
>  
>  	copy_user_test();
> -	kasan_workqueue_uaf();
>  
>  	kasan_restore_multi_shot(multishot);
>  	return -EAGAIN;
> -- 
> 2.25.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH mm 1/3] kasan: switch kunit tests to console tracepoints
  2022-09-27 13:13 ` [PATCH mm 1/3] kasan: switch kunit tests to console tracepoints Marco Elver
@ 2022-09-27 17:09   ` Andrey Konovalov
  0 siblings, 0 replies; 7+ messages in thread
From: Andrey Konovalov @ 2022-09-27 17:09 UTC (permalink / raw)
  To: Marco Elver
  Cc: andrey.konovalov, Alexander Potapenko, Dmitry Vyukov,
	Andrey Ryabinin, kasan-dev, Andrew Morton,
	Linux Memory Management List, LKML, Andrey Konovalov

On Tue, Sep 27, 2022 at 3:13 PM Marco Elver <elver@google.com> wrote:
>
> > -static struct kunit_resource resource;
> > -static struct kunit_kasan_status test_status;
>
> Also remove this struct from kasan.h?

Done in v2. Thank you, Marco!


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2022-09-27 17:09 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-24 18:31 [PATCH mm 1/3] kasan: switch kunit tests to console tracepoints andrey.konovalov
2022-09-24 18:31 ` [PATCH mm 2/3] kasan: migrate kasan_rcu_uaf test to kunit andrey.konovalov
2022-09-27 13:16   ` Marco Elver
2022-09-24 18:31 ` [PATCH mm 3/3] kasan: migrate workqueue_uaf " andrey.konovalov
2022-09-27 13:17   ` Marco Elver
2022-09-27 13:13 ` [PATCH mm 1/3] kasan: switch kunit tests to console tracepoints Marco Elver
2022-09-27 17:09   ` Andrey Konovalov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).