[PATCH] kunit: Fix a null-ptr-deref bug in kunit_run_case_catch_errors()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Inject fault while probing kunit-test.ko, the below null-ptr-deref
occurs.

In kunit_run_case_catch_errors(), if the first kunit_try_catch_run()
fails in kthread_run(), the kunit_try_run_case() will not run, so the
kunit_resource_test_init() and kunit_resource_test_cases() will not
run. And if the second call of kunit_try_catch_run() succeeds, it
will call kunit_resource_test_exit(), but the test->priv is NULL, call
kunit_cleanup() will cause below null-ptr-deref.

So just return the error code if the first kunit_try_catch_run()
fails.

 BUG: KASAN: null-ptr-deref in _raw_spin_lock_irqsave+0x7e/0xe0
 Write of size 4 at addr 0000000000000054 by task kunit_try_catch/10476

 CPU: 2 PID: 10476 Comm: kunit_try_catch Tainted: G        W        N 6.6.0-rc1+ #77
 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014
 Call Trace:
  <TASK>
  dump_stack_lvl+0x33/0x50
  print_report+0x3e5/0x600
  ? dequeue_entity+0x3c1/0x11e0
  ? rcu_trc_cmpxchg_need_qs+0x5e/0xa0
  ? _raw_spin_lock_irqsave+0x7e/0xe0
  kasan_report+0x90/0xc0
  ? _raw_spin_lock_irqsave+0x7e/0xe0
  kasan_check_range+0xe9/0x190
  _raw_spin_lock_irqsave+0x7e/0xe0
  ? _raw_read_lock_bh+0x40/0x40
  ? _raw_spin_lock_irqsave+0x8d/0xe0
  kunit_cleanup+0x77/0x110
  kunit_resource_test_exit+0x2c/0x50 [kunit_test]
  ? __kthread_parkme+0x8b/0x160
  kunit_try_run_case_cleanup+0xac/0xe0
  ? kunit_cleanup+0x110/0x110
  kunit_generic_run_threadfn_adapter+0x4a/0x90
  ? kunit_try_catch_throw+0x80/0x80
  kthread+0x2b6/0x380
  ? kthread_complete_and_exit+0x20/0x20
  ret_from_fork+0x2d/0x70
  ? kthread_complete_and_exit+0x20/0x20
  ret_from_fork_asm+0x11/0x20
  </TASK>
 ==================================================================
 Disabling lock debugging due to kernel taint
 BUG: kernel NULL pointer dereference, address: 0000000000000054
 #PF: supervisor write access in kernel mode
 #PF: error_code(0x0002) - not-present page
 PGD 0 P4D 0
 Oops: 0002 [#1] PREEMPT SMP KASAN
 CPU: 2 PID: 10476 Comm: kunit_try_catch Tainted: G    B   W        N 6.6.0-rc1+ #77
 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014
 RIP: 0010:_raw_spin_lock_irqsave+0x96/0xe0
 Code: 00 00 48 89 ef c7 44 24 20 00 00 00 00 e8 c2 02 88 fd be 04 00 00 00 48 8d 7c 24 20 e8 b3 02 88 fd ba 01 00 00 00 8b 44 24 20 <f0> 0f b1 55 00 75 2e 48 b8 00 00 00 00 00 fc ff df 48 c7 04 03 00
 RSP: 0018:ffff888108d07de0 EFLAGS: 00010097
 RAX: 0000000000000000 RBX: 1ffff110211a0fbc RCX: ffffffff840a0c9d
 RDX: 0000000000000001 RSI: 0000000000000004 RDI: ffff888108d07e00
 RBP: 0000000000000054 R08: ffffed10211a0fc0 R09: ffffed10211a0fc1
 R10: ffffed10211a0fc0 R11: 0000000000000003 R12: 0000000000000246
 R13: dffffc0000000000 R14: ffff88810dbdf590 R15: 0000000000000054
 FS:  0000000000000000(0000) GS:ffff888119f00000(0000) knlGS:0000000000000000
 CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
 CR2: 0000000000000054 CR3: 0000000107a31002 CR4: 0000000000170ee0
 DR0: ffffffff8faefce8 DR1: ffffffff8faefce9 DR2: ffffffff8faefcea
 DR3: ffffffff8faefceb DR6: 00000000ffff0ff0 DR7: 0000000000000600
 Call Trace:
  <TASK>
  ? __die_body+0x1b/0x60
  ? page_fault_oops+0x238/0x760
  ? page_fault_oops+0x760/0x760
  ? spurious_kernel_fault+0x2d0/0x2d0
  ? search_bpf_extables+0x134/0x190
  ? fixup_exception+0x4a/0xa20
  ? do_user_addr_fault+0xaa/0x1180
  ? exc_page_fault+0x5a/0xd0
  ? asm_exc_page_fault+0x22/0x30
  ? _raw_spin_lock_irqsave+0x8d/0xe0
  ? _raw_spin_lock_irqsave+0x96/0xe0
  ? _raw_read_lock_bh+0x40/0x40
  ? _raw_spin_lock_irqsave+0x8d/0xe0
  kunit_cleanup+0x77/0x110
  kunit_resource_test_exit+0x2c/0x50 [kunit_test]
  ? __kthread_parkme+0x8b/0x160
  kunit_try_run_case_cleanup+0xac/0xe0
  ? kunit_cleanup+0x110/0x110
  kunit_generic_run_threadfn_adapter+0x4a/0x90
  ? kunit_try_catch_throw+0x80/0x80
  kthread+0x2b6/0x380
  ? kthread_complete_and_exit+0x20/0x20
  ret_from_fork+0x2d/0x70
  ? kthread_complete_and_exit+0x20/0x20
  ret_from_fork_asm+0x11/0x20
  </TASK>
 Modules linked in: kunit_test(+) [last unloaded: kunit_test]
 Dumping ftrace buffer:
    (ftrace buffer empty)
 CR2: 0000000000000054
 ---[ end trace 0000000000000000 ]---
 RIP: 0010:_raw_spin_lock_irqsave+0x96/0xe0
 Code: 00 00 48 89 ef c7 44 24 20 00 00 00 00 e8 c2 02 88 fd be 04 00 00 00 48 8d 7c 24 20 e8 b3 02 88 fd ba 01 00 00 00 8b 44 24 20 <f0> 0f b1 55 00 75 2e 48 b8 00 00 00 00 00 fc ff df 48 c7 04 03 00
 RSP: 0018:ffff888108d07de0 EFLAGS: 00010097
 RAX: 0000000000000000 RBX: 1ffff110211a0fbc RCX: ffffffff840a0c9d
 RDX: 0000000000000001 RSI: 0000000000000004 RDI: ffff888108d07e00
 RBP: 0000000000000054 R08: ffffed10211a0fc0 R09: ffffed10211a0fc1
 R10: ffffed10211a0fc0 R11: 0000000000000003 R12: 0000000000000246
 R13: dffffc0000000000 R14: ffff88810dbdf590 R15: 0000000000000054
 FS:  0000000000000000(0000) GS:ffff888119f00000(0000) knlGS:0000000000000000
 CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
 CR2: 0000000000000054 CR3: 0000000107a31002 CR4: 0000000000170ee0
 DR0: ffffffff8faefce8 DR1: ffffffff8faefce9 DR2: ffffffff8faefcea
 DR3: ffffffff8faefceb DR6: 00000000ffff0ff0 DR7: 0000000000000600
 Kernel panic - not syncing: Fatal exception
 Dumping ftrace buffer:
    (ftrace buffer empty)
 Kernel Offset: disabled
 Rebooting in 1 seconds..

Fixes: 55e8c1b49ac5 ("kunit: Always run cleanup from a test kthread")
Signed-off-by: Jinjie Ruan <ruanjinjie@xxxxxxxxxx>
---
 include/kunit/try-catch.h | 2 +-
 lib/kunit/test.c          | 6 +++++-
 lib/kunit/try-catch.c     | 9 ++++++---
 3 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/include/kunit/try-catch.h b/include/kunit/try-catch.h
index c507dd43119d..5192b8e0aac6 100644
--- a/include/kunit/try-catch.h
+++ b/include/kunit/try-catch.h
@@ -53,7 +53,7 @@ struct kunit_try_catch {
 	void *context;
 };
 
-void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context);
+int kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context);
 
 void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch);
 
diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index 421f13981412..f20cce96a971 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -512,6 +512,7 @@ static void kunit_run_case_catch_errors(struct kunit_suite *suite,
 {
 	struct kunit_try_catch_context context;
 	struct kunit_try_catch *try_catch;
+	int ret = 0;
 
 	try_catch = &test->try_catch;
 
@@ -522,7 +523,9 @@ static void kunit_run_case_catch_errors(struct kunit_suite *suite,
 	context.test = test;
 	context.suite = suite;
 	context.test_case = test_case;
-	kunit_try_catch_run(try_catch, &context);
+	ret = kunit_try_catch_run(try_catch, &context);
+	if (ret)
+		goto out;
 
 	/* Now run the cleanup */
 	kunit_try_catch_init(try_catch,
@@ -531,6 +534,7 @@ static void kunit_run_case_catch_errors(struct kunit_suite *suite,
 			     kunit_catch_run_case_cleanup);
 	kunit_try_catch_run(try_catch, &context);
 
+out:
 	/* Propagate the parameter result to the test case. */
 	if (test->status == KUNIT_FAILURE)
 		test_case->status = KUNIT_FAILURE;
diff --git a/lib/kunit/try-catch.c b/lib/kunit/try-catch.c
index f7825991d576..b937da7ec0a4 100644
--- a/lib/kunit/try-catch.c
+++ b/lib/kunit/try-catch.c
@@ -55,7 +55,7 @@ static unsigned long kunit_test_timeout(void)
 	return 300 * msecs_to_jiffies(MSEC_PER_SEC); /* 5 min */
 }
 
-void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context)
+int kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context)
 {
 	DECLARE_COMPLETION_ONSTACK(try_completion);
 	struct kunit *test = try_catch->test;
@@ -70,7 +70,8 @@ void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context)
 				  "kunit_try_catch_thread");
 	if (IS_ERR(task_struct)) {
 		try_catch->catch(try_catch->context);
-		return;
+		try_catch->try_result = -EINTR;
+		return PTR_ERR(task_struct);
 	}
 
 	time_remaining = wait_for_completion_timeout(&try_completion,
@@ -84,7 +85,7 @@ void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context)
 	exit_code = try_catch->try_result;
 
 	if (!exit_code)
-		return;
+		return 0;
 
 	if (exit_code == -EFAULT)
 		try_catch->try_result = 0;
@@ -94,5 +95,7 @@ void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context)
 		kunit_err(test, "Unknown error: %d\n", exit_code);
 
 	try_catch->catch(try_catch->context);
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(kunit_try_catch_run);
-- 
2.34.1




[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux