From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 668108F58 for ; Wed, 17 Sep 2025 00:29:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1758068947; cv=none; b=JdjAisfDoCTppM/fpGH0XJvuFCVoJNJlZcaoKRh3eyjEDfIHcXlNP26TfZwPzdlL8nqiyxmZ+FaiMEToKdPSHQDzNAJox+M5dCPuHRD0BzPn7tTr3hk1ais0v4IkPUFAnjo2vPbTdcTVaaH8/Afz+fMCA0xp+BwMKlGGEncFDnY= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1758068947; c=relaxed/simple; bh=rvjVYixkMt5rwC74ouo1ogt5wlyh20RsgfPBbRQxzoU=; h=Date:To:From:Subject:Message-Id; b=X9HyRiFGohIfe0bPZzwICkavx1ETTSH442d9P3S1aUs9sV7BlA8EwqsDfb3PxVdcQLxeXkPYM4BYfW2+W05gKmek/pZRYYznvvoilUiaiLxTTu9wpUUHnHVzRRhvcwtkXXJ9MOgw1tbh93R9FarjlI55zUhr0nCHirFku/NBLu0= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux-foundation.org header.i=@linux-foundation.org header.b=R3lWectc; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux-foundation.org header.i=@linux-foundation.org header.b="R3lWectc" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E06C0C4CEEB; Wed, 17 Sep 2025 00:29:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linux-foundation.org; s=korg; t=1758068947; bh=rvjVYixkMt5rwC74ouo1ogt5wlyh20RsgfPBbRQxzoU=; h=Date:To:From:Subject:From; b=R3lWectcppiBgY/lD5s6ZA2qmWHg7dFSCO4qTzU7MxL0X0Iq0TGHRKfdRxJMLMWnB 5rGImpNoWVRD4PHN+VPd/sK3s5GdUkHQ75qZY+aGlUFXqDiipROwVE9mPXUC9qLiJQ QJRQ0zevEyBQVenasukyY1uNMwrHDYjA/eNZ1H58= Date: Tue, 16 Sep 2025 17:29:06 -0700 To: mm-commits@vger.kernel.org,yang@os.amperecomputing.com,will@kernel.org,vincenzo.frascino@arm.com,scott@os.amperecomputing.com,ryabinin.a.a@gmail.com,pankaj.gupta@amd.com,oliver.upton@linux.dev,maz@kernel.org,leitao@debian.org,kaleshsingh@google.com,jhubbard@nvidia.com,james.morse@arm.com,hardevsinh.palaniya@siliconsignals.io,glider@google.com,dvyukov@google.com,david@redhat.com,corbet@lwn.net,catalin.marinas@arm.com,broonie@kernel.org,ardb@kernel.org,andreyknvl@gmail.com,yeoreum.yun@arm.com,akpm@linux-foundation.org From: Andrew Morton Subject: + kasan-apply-write-only-mode-in-kasan-kunit-testcases.patch added to mm-unstable branch Message-Id: <20250917002906.E06C0C4CEEB@smtp.kernel.org> Precedence: bulk X-Mailing-List: mm-commits@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: The patch titled Subject: kasan: apply write-only mode in kasan kunit testcases has been added to the -mm mm-unstable branch. Its filename is kasan-apply-write-only-mode-in-kasan-kunit-testcases.patch This patch will shortly appear at https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/kasan-apply-write-only-mode-in-kasan-kunit-testcases.patch This patch will later appear in the mm-unstable branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next via the mm-everything branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm and is updated there every 2-3 working days ------------------------------------------------------ From: Yeoreum Yun Subject: kasan: apply write-only mode in kasan kunit testcases Date: Tue, 16 Sep 2025 23:27:55 +0100 When KASAN is configured in write-only mode, fetch/load operations do not trigger tag check faults. As a result, the outcome of some test cases may differ compared to when KASAN is configured without write-only mode. Therefore, by modifying pre-exist testcases check the write only makes tag check fault (TCF) where writing is perform in "allocated memory" but tag is invalid (i.e) redzone write in atomic_set() testcases. Otherwise check the invalid fetch/read doesn't generate TCF. Also, skip some testcases affected by initial value (i.e) atomic_cmpxchg() testcase maybe successd if it passes valid atomic_t address and invalid oldaval address. In this case, if invalid atomic_t doesn't have the same oldval, it won't trigger write operation so the test will pass. Link: https://lkml.kernel.org/r/20250916222755.466009-3-yeoreum.yun@arm.com Signed-off-by: Yeoreum Yun Reviewed-by: Andrey Konovalov Cc: Alexander Potapenko Cc: Andrey Ryabinin Cc: Ard Biesheuvel Cc: Breno Leitao Cc: Catalin Marinas Cc: David Hildenbrand Cc: Dmitriy Vyukov Cc: D Scott Phillips Cc: Hardevsinh Palaniya Cc: James Morse Cc: John Hubbard Cc: Jonathan Corbet Cc: Kalesh Singh Cc: Marc Zyngier Cc: Mark Brown Cc: Oliver Upton Cc: Pankaj Gupta Cc: Vincenzo Frascino Cc: Will Deacon Cc: Yang Shi Signed-off-by: Andrew Morton --- mm/kasan/kasan_test_c.c | 205 +++++++++++++++++++++++++------------- 1 file changed, 136 insertions(+), 69 deletions(-) --- a/mm/kasan/kasan_test_c.c~kasan-apply-write-only-mode-in-kasan-kunit-testcases +++ a/mm/kasan/kasan_test_c.c @@ -94,11 +94,14 @@ static void kasan_test_exit(struct kunit } /** - * KUNIT_EXPECT_KASAN_FAIL - check that the executed expression produces a - * KASAN report; causes a KUnit test failure otherwise. + * KUNIT_EXPECT_KASAN_RESULT - checks whether the executed expression + * produces a KASAN report; causes a KUnit test failure when the result + * is different from @fail. * * @test: Currently executing KUnit test. - * @expression: Expression that must produce a KASAN report. + * @expr: Expression to be tested. + * @expr_str: Expression to be tested encoded as a string. + * @fail: Whether expression should produce a KASAN report. * * For hardware tag-based KASAN, when a synchronous tag fault happens, tag * checking is auto-disabled. When this happens, this test handler reenables @@ -110,25 +113,29 @@ static void kasan_test_exit(struct kunit * Use READ/WRITE_ONCE() for the accesses and compiler barriers around the * expression to prevent that. * - * In between KUNIT_EXPECT_KASAN_FAIL checks, test_status.report_found is kept + * In between KUNIT_EXPECT_KASAN_RESULT checks, test_status.report_found is kept * as false. This allows detecting KASAN reports that happen outside of the * checks by asserting !test_status.report_found at the start of - * KUNIT_EXPECT_KASAN_FAIL and in kasan_test_exit. + * KUNIT_EXPECT_KASAN_RESULT and in kasan_test_exit. */ -#define KUNIT_EXPECT_KASAN_FAIL(test, expression) do { \ +#define KUNIT_EXPECT_KASAN_RESULT(test, expr, expr_str, fail) \ +do { \ if (IS_ENABLED(CONFIG_KASAN_HW_TAGS) && \ kasan_sync_fault_possible()) \ migrate_disable(); \ KUNIT_EXPECT_FALSE(test, READ_ONCE(test_status.report_found)); \ barrier(); \ - expression; \ + expr; \ barrier(); \ if (kasan_async_fault_possible()) \ kasan_force_async_fault(); \ - if (!READ_ONCE(test_status.report_found)) { \ - KUNIT_FAIL(test, KUNIT_SUBTEST_INDENT "KASAN failure " \ - "expected in \"" #expression \ - "\", but none occurred"); \ + if (READ_ONCE(test_status.report_found) != fail) { \ + KUNIT_FAIL(test, KUNIT_SUBTEST_INDENT "KASAN failure" \ + "%sexpected in \"" expr_str \ + "\", but %soccurred", \ + (fail ? " " : " not "), \ + (test_status.report_found ? \ + "" : "none ")); \ } \ if (IS_ENABLED(CONFIG_KASAN_HW_TAGS) && \ kasan_sync_fault_possible()) { \ @@ -141,6 +148,34 @@ static void kasan_test_exit(struct kunit WRITE_ONCE(test_status.async_fault, false); \ } while (0) +/* + * KUNIT_EXPECT_KASAN_FAIL - check that the executed expression produces a + * KASAN report; causes a KUnit test failure otherwise. + * + * @test: Currently executing KUnit test. + * @expr: Expression that must produce a KASAN report. + */ +#define KUNIT_EXPECT_KASAN_FAIL(test, expr) \ + KUNIT_EXPECT_KASAN_RESULT(test, expr, #expr, true) + +/* + * KUNIT_EXPECT_KASAN_FAIL_READ - check that the executed expression + * produces a KASAN report when the write-only mode is not enabled; + * causes a KUnit test failure otherwise. + * + * Note: At the moment, this macro does not check whether the produced + * KASAN report is a report about a bad read access. It is only intended + * for checking the write-only KASAN mode functionality without failing + * KASAN tests. + * + * @test: Currently executing KUnit test. + * @expr: Expression that must only produce a KASAN report + * when the write-only mode is not enabled. + */ +#define KUNIT_EXPECT_KASAN_FAIL_READ(test, expr) \ + KUNIT_EXPECT_KASAN_RESULT(test, expr, #expr, \ + !kasan_write_only_enabled()) \ + #define KASAN_TEST_NEEDS_CONFIG_ON(test, config) do { \ if (!IS_ENABLED(config)) \ kunit_skip((test), "Test requires " #config "=y"); \ @@ -183,8 +218,8 @@ static void kmalloc_oob_right(struct kun KUNIT_EXPECT_KASAN_FAIL(test, ptr[size + 5] = 'y'); /* Out-of-bounds access past the aligned kmalloc object. */ - KUNIT_EXPECT_KASAN_FAIL(test, ptr[0] = - ptr[size + KASAN_GRANULE_SIZE + 5]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, ptr[0] = + ptr[size + KASAN_GRANULE_SIZE + 5]); kfree(ptr); } @@ -198,7 +233,7 @@ static void kmalloc_oob_left(struct kuni KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr); OPTIMIZER_HIDE_VAR(ptr); - KUNIT_EXPECT_KASAN_FAIL(test, *ptr = *(ptr - 1)); + KUNIT_EXPECT_KASAN_FAIL_READ(test, *ptr = *(ptr - 1)); kfree(ptr); } @@ -211,7 +246,7 @@ static void kmalloc_node_oob_right(struc KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr); OPTIMIZER_HIDE_VAR(ptr); - KUNIT_EXPECT_KASAN_FAIL(test, ptr[0] = ptr[size]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, ptr[0] = ptr[size]); kfree(ptr); } @@ -291,7 +326,7 @@ static void kmalloc_large_uaf(struct kun KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr); kfree(ptr); - KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[0]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)ptr)[0]); } static void kmalloc_large_invalid_free(struct kunit *test) @@ -323,7 +358,7 @@ static void page_alloc_oob_right(struct ptr = page_address(pages); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr); - KUNIT_EXPECT_KASAN_FAIL(test, ptr[0] = ptr[size]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, ptr[0] = ptr[size]); free_pages((unsigned long)ptr, order); } @@ -338,7 +373,7 @@ static void page_alloc_uaf(struct kunit KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr); free_pages((unsigned long)ptr, order); - KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[0]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)ptr)[0]); } static void krealloc_more_oob_helper(struct kunit *test, @@ -458,7 +493,7 @@ static void krealloc_uaf(struct kunit *t KUNIT_EXPECT_KASAN_FAIL(test, ptr2 = krealloc(ptr1, size2, GFP_KERNEL)); KUNIT_ASSERT_NULL(test, ptr2); - KUNIT_EXPECT_KASAN_FAIL(test, *(volatile char *)ptr1); + KUNIT_EXPECT_KASAN_FAIL_READ(test, *(volatile char *)ptr1); } static void kmalloc_oob_16(struct kunit *test) @@ -501,7 +536,7 @@ static void kmalloc_uaf_16(struct kunit KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr2); kfree(ptr2); - KUNIT_EXPECT_KASAN_FAIL(test, *ptr1 = *ptr2); + KUNIT_EXPECT_KASAN_FAIL_READ(test, *ptr1 = *ptr2); kfree(ptr1); } @@ -640,8 +675,8 @@ static void kmalloc_memmove_invalid_size memset((char *)ptr, 0, 64); OPTIMIZER_HIDE_VAR(ptr); OPTIMIZER_HIDE_VAR(invalid_size); - KUNIT_EXPECT_KASAN_FAIL(test, - memmove((char *)ptr, (char *)ptr + 4, invalid_size)); + KUNIT_EXPECT_KASAN_FAIL_READ(test, + memmove((char *)ptr, (char *)ptr + 4, invalid_size)); kfree(ptr); } @@ -654,7 +689,7 @@ static void kmalloc_uaf(struct kunit *te KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr); kfree(ptr); - KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[8]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)ptr)[8]); } static void kmalloc_uaf_memset(struct kunit *test) @@ -701,7 +736,7 @@ again: goto again; } - KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr1)[40]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)ptr1)[40]); KUNIT_EXPECT_PTR_NE(test, ptr1, ptr2); kfree(ptr2); @@ -727,19 +762,19 @@ static void kmalloc_uaf3(struct kunit *t KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr2); kfree(ptr2); - KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr1)[8]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)ptr1)[8]); } static void kasan_atomics_helper(struct kunit *test, void *unsafe, void *safe) { int *i_unsafe = unsafe; - KUNIT_EXPECT_KASAN_FAIL(test, READ_ONCE(*i_unsafe)); + KUNIT_EXPECT_KASAN_FAIL_READ(test, READ_ONCE(*i_unsafe)); KUNIT_EXPECT_KASAN_FAIL(test, WRITE_ONCE(*i_unsafe, 42)); - KUNIT_EXPECT_KASAN_FAIL(test, smp_load_acquire(i_unsafe)); + KUNIT_EXPECT_KASAN_FAIL_READ(test, smp_load_acquire(i_unsafe)); KUNIT_EXPECT_KASAN_FAIL(test, smp_store_release(i_unsafe, 42)); - KUNIT_EXPECT_KASAN_FAIL(test, atomic_read(unsafe)); + KUNIT_EXPECT_KASAN_FAIL_READ(test, atomic_read(unsafe)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_set(unsafe, 42)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_add(42, unsafe)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_sub(42, unsafe)); @@ -752,18 +787,31 @@ static void kasan_atomics_helper(struct KUNIT_EXPECT_KASAN_FAIL(test, atomic_xchg(unsafe, 42)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_cmpxchg(unsafe, 21, 42)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_try_cmpxchg(unsafe, safe, 42)); - KUNIT_EXPECT_KASAN_FAIL(test, atomic_try_cmpxchg(safe, unsafe, 42)); + /* + * The result of the test below may vary due to garbage values of + * unsafe in write-only mode. + * Therefore, skip this test when KASAN is configured in write-only mode. + */ + if (!kasan_write_only_enabled()) + KUNIT_EXPECT_KASAN_FAIL(test, atomic_try_cmpxchg(safe, unsafe, 42)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_sub_and_test(42, unsafe)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_dec_and_test(unsafe)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_inc_and_test(unsafe)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_add_negative(42, unsafe)); - KUNIT_EXPECT_KASAN_FAIL(test, atomic_add_unless(unsafe, 21, 42)); - KUNIT_EXPECT_KASAN_FAIL(test, atomic_inc_not_zero(unsafe)); - KUNIT_EXPECT_KASAN_FAIL(test, atomic_inc_unless_negative(unsafe)); - KUNIT_EXPECT_KASAN_FAIL(test, atomic_dec_unless_positive(unsafe)); - KUNIT_EXPECT_KASAN_FAIL(test, atomic_dec_if_positive(unsafe)); + /* + * The result of the test below may vary due to garbage values of + * unsafe in write-only mode. + * Therefore, skip this test when KASAN is configured in write-only mode. + */ + if (!kasan_write_only_enabled()) { + KUNIT_EXPECT_KASAN_FAIL(test, atomic_add_unless(unsafe, 21, 42)); + KUNIT_EXPECT_KASAN_FAIL(test, atomic_inc_not_zero(unsafe)); + KUNIT_EXPECT_KASAN_FAIL(test, atomic_inc_unless_negative(unsafe)); + KUNIT_EXPECT_KASAN_FAIL(test, atomic_dec_unless_positive(unsafe)); + KUNIT_EXPECT_KASAN_FAIL(test, atomic_dec_if_positive(unsafe)); + } - KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_read(unsafe)); + KUNIT_EXPECT_KASAN_FAIL_READ(test, atomic_long_read(unsafe)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_set(unsafe, 42)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_add(42, unsafe)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_sub(42, unsafe)); @@ -776,16 +824,29 @@ static void kasan_atomics_helper(struct KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_xchg(unsafe, 42)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_cmpxchg(unsafe, 21, 42)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_try_cmpxchg(unsafe, safe, 42)); - KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_try_cmpxchg(safe, unsafe, 42)); + /* + * The result of the test below may vary due to garbage values of + * unsafe in write-only mode. + * Therefore, skip this test when KASAN is configured in write-only mode. + */ + if (!kasan_write_only_enabled()) + KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_try_cmpxchg(safe, unsafe, 42)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_sub_and_test(42, unsafe)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_dec_and_test(unsafe)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_inc_and_test(unsafe)); KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_add_negative(42, unsafe)); - KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_add_unless(unsafe, 21, 42)); - KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_inc_not_zero(unsafe)); - KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_inc_unless_negative(unsafe)); - KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_dec_unless_positive(unsafe)); - KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_dec_if_positive(unsafe)); + /* + * The result of the test below may vary due to garbage values of + * unsafe in write-only mode. + * Therefore, skip this test when KASAN is configured in write-only mode. + */ + if (!kasan_write_only_enabled()) { + KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_add_unless(unsafe, 21, 42)); + KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_inc_not_zero(unsafe)); + KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_inc_unless_negative(unsafe)); + KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_dec_unless_positive(unsafe)); + KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_dec_if_positive(unsafe)); + } } static void kasan_atomics(struct kunit *test) @@ -842,8 +903,8 @@ static void ksize_unpoisons_memory(struc /* These must trigger a KASAN report. */ if (IS_ENABLED(CONFIG_KASAN_GENERIC)) KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[size]); - KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[size + 5]); - KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[real_size - 1]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)ptr)[size + 5]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)ptr)[real_size - 1]); kfree(ptr); } @@ -863,8 +924,8 @@ static void ksize_uaf(struct kunit *test OPTIMIZER_HIDE_VAR(ptr); KUNIT_EXPECT_KASAN_FAIL(test, ksize(ptr)); - KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[0]); - KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[size]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)ptr)[0]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)ptr)[size]); } /* @@ -899,9 +960,9 @@ static void rcu_uaf(struct kunit *test) 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()); + KUNIT_EXPECT_KASAN_FAIL_READ(test, + call_rcu(&global_rcu_ptr->rcu, rcu_uaf_reclaim); + rcu_barrier()); } static void workqueue_uaf_work(struct work_struct *work) @@ -924,8 +985,8 @@ static void workqueue_uaf(struct kunit * queue_work(workqueue, work); destroy_workqueue(workqueue); - KUNIT_EXPECT_KASAN_FAIL(test, - ((volatile struct work_struct *)work)->data); + KUNIT_EXPECT_KASAN_FAIL_READ(test, + ((volatile struct work_struct *)work)->data); } static void kfree_via_page(struct kunit *test) @@ -972,7 +1033,7 @@ static void kmem_cache_oob(struct kunit return; } - KUNIT_EXPECT_KASAN_FAIL(test, *p = p[size + OOB_TAG_OFF]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, *p = p[size + OOB_TAG_OFF]); kmem_cache_free(cache, p); kmem_cache_destroy(cache); @@ -1068,7 +1129,7 @@ static void kmem_cache_rcu_uaf(struct ku */ rcu_barrier(); - KUNIT_EXPECT_KASAN_FAIL(test, READ_ONCE(*p)); + KUNIT_EXPECT_KASAN_FAIL_READ(test, READ_ONCE(*p)); kmem_cache_destroy(cache); } @@ -1246,7 +1307,7 @@ static void mempool_oob_right_helper(str KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)&elem[size])[0]); else - KUNIT_EXPECT_KASAN_FAIL(test, + KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)&elem[round_up(size, KASAN_GRANULE_SIZE)])[0]); mempool_free(elem, pool); @@ -1312,7 +1373,7 @@ static void mempool_uaf_helper(struct ku mempool_free(elem, pool); ptr = page ? page_address((struct page *)elem) : elem; - KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[0]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)ptr)[0]); } static void mempool_kmalloc_uaf(struct kunit *test) @@ -1571,7 +1632,7 @@ static void kasan_memchr(struct kunit *t OPTIMIZER_HIDE_VAR(ptr); OPTIMIZER_HIDE_VAR(size); - KUNIT_EXPECT_KASAN_FAIL(test, + KUNIT_EXPECT_KASAN_FAIL_READ(test, kasan_ptr_result = memchr(ptr, '1', size + 1)); kfree(ptr); @@ -1598,7 +1659,7 @@ static void kasan_memcmp(struct kunit *t OPTIMIZER_HIDE_VAR(ptr); OPTIMIZER_HIDE_VAR(size); - KUNIT_EXPECT_KASAN_FAIL(test, + KUNIT_EXPECT_KASAN_FAIL_READ(test, kasan_int_result = memcmp(ptr, arr, size+1)); kfree(ptr); } @@ -1635,7 +1696,7 @@ static void kasan_strings(struct kunit * strscpy(ptr, src + 1, KASAN_GRANULE_SIZE)); /* strscpy should fail if the first byte is unreadable. */ - KUNIT_EXPECT_KASAN_FAIL(test, strscpy(ptr, src + KASAN_GRANULE_SIZE, + KUNIT_EXPECT_KASAN_FAIL_READ(test, strscpy(ptr, src + KASAN_GRANULE_SIZE, KASAN_GRANULE_SIZE)); kfree(src); @@ -1648,17 +1709,17 @@ static void kasan_strings(struct kunit * * will likely point to zeroed byte. */ ptr += 16; - KUNIT_EXPECT_KASAN_FAIL(test, kasan_ptr_result = strchr(ptr, '1')); + KUNIT_EXPECT_KASAN_FAIL_READ(test, kasan_ptr_result = strchr(ptr, '1')); - KUNIT_EXPECT_KASAN_FAIL(test, kasan_ptr_result = strrchr(ptr, '1')); + KUNIT_EXPECT_KASAN_FAIL_READ(test, kasan_ptr_result = strrchr(ptr, '1')); - KUNIT_EXPECT_KASAN_FAIL(test, kasan_int_result = strcmp(ptr, "2")); + KUNIT_EXPECT_KASAN_FAIL_READ(test, kasan_int_result = strcmp(ptr, "2")); - KUNIT_EXPECT_KASAN_FAIL(test, kasan_int_result = strncmp(ptr, "2", 1)); + KUNIT_EXPECT_KASAN_FAIL_READ(test, kasan_int_result = strncmp(ptr, "2", 1)); - KUNIT_EXPECT_KASAN_FAIL(test, kasan_int_result = strlen(ptr)); + KUNIT_EXPECT_KASAN_FAIL_READ(test, kasan_int_result = strlen(ptr)); - KUNIT_EXPECT_KASAN_FAIL(test, kasan_int_result = strnlen(ptr, 1)); + KUNIT_EXPECT_KASAN_FAIL_READ(test, kasan_int_result = strnlen(ptr, 1)); } static void kasan_bitops_modify(struct kunit *test, int nr, void *addr) @@ -1677,12 +1738,18 @@ static void kasan_bitops_test_and_modify { KUNIT_EXPECT_KASAN_FAIL(test, test_and_set_bit(nr, addr)); KUNIT_EXPECT_KASAN_FAIL(test, __test_and_set_bit(nr, addr)); - KUNIT_EXPECT_KASAN_FAIL(test, test_and_set_bit_lock(nr, addr)); + /* + * When KASAN is running in write-only mode, + * a fault won't occur when the bit is set. + * Therefore, skip the test_and_set_bit_lock test in write-only mode. + */ + if (!kasan_write_only_enabled()) + KUNIT_EXPECT_KASAN_FAIL(test, test_and_set_bit_lock(nr, addr)); KUNIT_EXPECT_KASAN_FAIL(test, test_and_clear_bit(nr, addr)); KUNIT_EXPECT_KASAN_FAIL(test, __test_and_clear_bit(nr, addr)); KUNIT_EXPECT_KASAN_FAIL(test, test_and_change_bit(nr, addr)); KUNIT_EXPECT_KASAN_FAIL(test, __test_and_change_bit(nr, addr)); - KUNIT_EXPECT_KASAN_FAIL(test, kasan_int_result = test_bit(nr, addr)); + KUNIT_EXPECT_KASAN_FAIL_READ(test, kasan_int_result = test_bit(nr, addr)); if (nr < 7) KUNIT_EXPECT_KASAN_FAIL(test, kasan_int_result = xor_unlock_is_negative_byte(1 << nr, addr)); @@ -1806,7 +1873,7 @@ static void vmalloc_oob(struct kunit *te KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)v_ptr)[size]); /* An aligned access into the first out-of-bounds granule. */ - KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)v_ptr)[size + 5]); + KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)v_ptr)[size + 5]); /* Check that in-bounds accesses to the physical page are valid. */ page = vmalloc_to_page(v_ptr); @@ -2083,15 +2150,15 @@ static void copy_user_test_oob(struct ku KUNIT_EXPECT_KASAN_FAIL(test, unused = copy_from_user(kmem, usermem, size + 1)); - KUNIT_EXPECT_KASAN_FAIL(test, + KUNIT_EXPECT_KASAN_FAIL_READ(test, unused = copy_to_user(usermem, kmem, size + 1)); KUNIT_EXPECT_KASAN_FAIL(test, unused = __copy_from_user(kmem, usermem, size + 1)); - KUNIT_EXPECT_KASAN_FAIL(test, + KUNIT_EXPECT_KASAN_FAIL_READ(test, unused = __copy_to_user(usermem, kmem, size + 1)); KUNIT_EXPECT_KASAN_FAIL(test, unused = __copy_from_user_inatomic(kmem, usermem, size + 1)); - KUNIT_EXPECT_KASAN_FAIL(test, + KUNIT_EXPECT_KASAN_FAIL_READ(test, unused = __copy_to_user_inatomic(usermem, kmem, size + 1)); /* _ Patches currently in -mm which might be from yeoreum.yun@arm.com are kasan-hw-tags-introduce-kasanwrite_only-option.patch kasan-apply-write-only-mode-in-kasan-kunit-testcases.patch