From: Andrey Konovalov <andreyknvl@gmail.com>
To: Yeoreum Yun <yeoreum.yun@arm.com>
Cc: ryabinin.a.a@gmail.com, glider@google.com, dvyukov@google.com,
vincenzo.frascino@arm.com, corbet@lwn.net,
catalin.marinas@arm.com, will@kernel.org,
akpm@linux-foundation.org, scott@os.amperecomputing.com,
jhubbard@nvidia.com, pankaj.gupta@amd.com, leitao@debian.org,
kaleshsingh@google.com, maz@kernel.org, broonie@kernel.org,
oliver.upton@linux.dev, james.morse@arm.com, ardb@kernel.org,
hardevsinh.palaniya@siliconsignals.io, david@redhat.com,
yang@os.amperecomputing.com, kasan-dev@googlegroups.com,
workflows@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-mm@kvack.org
Subject: Re: [PATCH v6 2/2] kasan: apply write-only mode in kasan kunit testcases
Date: Wed, 3 Sep 2025 14:49:34 +0200 [thread overview]
Message-ID: <CA+fCnZeyKuet2XY9=jOdiK4Z6f4_=Xb5ZBzBaDL-2gFPv9yJ5A@mail.gmail.com> (raw)
In-Reply-To: <20250901104623.402172-3-yeoreum.yun@arm.com>
On Mon, Sep 1, 2025 at 12:46 PM Yeoreum Yun <yeoreum.yun@arm.com> wrote:
>
> 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.
>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> mm/kasan/kasan_test_c.c | 204 ++++++++++++++++++++++++++--------------
> 1 file changed, 135 insertions(+), 69 deletions(-)
>
> diff --git a/mm/kasan/kasan_test_c.c b/mm/kasan/kasan_test_c.c
> index e0968acc03aa..8b3bb33603e1 100644
> --- a/mm/kasan/kasan_test_c.c
> +++ b/mm/kasan/kasan_test_c.c
> @@ -94,11 +94,13 @@ static void kasan_test_exit(struct kunit *test)
> }
>
> /**
> - * KUNIT_EXPECT_KASAN_FAIL - check that the executed expression produces a
> - * KASAN report; causes a KUnit test failure otherwise.
> + * KUNIT_EXPECT_KASAN_RESULT - check that the executed expression
> + * causes a KUnit test failure when the result is different from @fail.
What I meant here was:
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 +112,29 @@ static void kasan_test_exit(struct kunit *test)
> * 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 +147,34 @@ static void kasan_test_exit(struct kunit *test)
> 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 +217,8 @@ static void kmalloc_oob_right(struct kunit *test)
> 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 +232,7 @@ static void kmalloc_oob_left(struct kunit *test)
> 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 +245,7 @@ static void kmalloc_node_oob_right(struct kunit *test)
> 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 +325,7 @@ static void kmalloc_large_uaf(struct kunit *test)
> 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 +357,7 @@ static void page_alloc_oob_right(struct kunit *test)
> 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 +372,7 @@ static void page_alloc_uaf(struct kunit *test)
> 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 +492,7 @@ static void krealloc_uaf(struct kunit *test)
>
> 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 +535,7 @@ static void kmalloc_uaf_16(struct kunit *test)
> 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 +674,8 @@ static void kmalloc_memmove_invalid_size(struct kunit *test)
> 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 +688,7 @@ static void kmalloc_uaf(struct kunit *test)
> 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 +735,7 @@ static void kmalloc_uaf2(struct kunit *test)
> 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 +761,19 @@ static void kmalloc_uaf3(struct kunit *test)
> 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 +786,31 @@ static void kasan_atomics_helper(struct kunit *test, void *unsafe, void *safe)
> 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 +823,29 @@ static void kasan_atomics_helper(struct kunit *test, void *unsafe, void *safe)
> 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 +902,8 @@ static void ksize_unpoisons_memory(struct kunit *test)
> /* 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 +923,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 +959,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 +984,8 @@ static void workqueue_uaf(struct kunit *test)
> 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 +1032,7 @@ static void kmem_cache_oob(struct kunit *test)
> 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 +1128,7 @@ static void kmem_cache_rcu_uaf(struct kunit *test)
> */
> rcu_barrier();
>
> - KUNIT_EXPECT_KASAN_FAIL(test, READ_ONCE(*p));
> + KUNIT_EXPECT_KASAN_FAIL_READ(test, READ_ONCE(*p));
>
> kmem_cache_destroy(cache);
> }
> @@ -1207,7 +1267,7 @@ static void mempool_oob_right_helper(struct kunit *test, mempool_t *pool, size_t
> 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);
> @@ -1273,7 +1333,7 @@ static void mempool_uaf_helper(struct kunit *test, mempool_t *pool, bool page)
> 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)
> @@ -1532,7 +1592,7 @@ static void kasan_memchr(struct kunit *test)
>
> 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);
> @@ -1559,7 +1619,7 @@ static void kasan_memcmp(struct kunit *test)
>
> 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);
> }
> @@ -1594,7 +1654,7 @@ static void kasan_strings(struct kunit *test)
> 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);
> @@ -1607,17 +1667,17 @@ static void kasan_strings(struct kunit *test)
> * 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)
> @@ -1636,12 +1696,18 @@ static void kasan_bitops_test_and_modify(struct kunit *test, int nr, void *addr)
> {
> 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));
> @@ -1765,7 +1831,7 @@ static void vmalloc_oob(struct kunit *test)
> 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);
> @@ -2042,15 +2108,15 @@ static void copy_user_test_oob(struct kunit *test)
>
> 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));
>
> /*
> --
> LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
>
Reviewed-by: Andrey Konovalov <andreyknvl@gmail.com>
next prev parent reply other threads:[~2025-09-03 12:49 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-01 10:46 [PATCH v6 0/2] introduce kasan.write_only option in hw-tags Yeoreum Yun
2025-09-01 10:46 ` [PATCH v6 1/2] kasan/hw-tags: introduce kasan.write_only option Yeoreum Yun
2025-09-01 16:53 ` Catalin Marinas
2025-09-01 19:23 ` Andrew Morton
2025-09-01 20:31 ` Yeoreum Yun
2025-09-01 10:46 ` [PATCH v6 2/2] kasan: apply write-only mode in kasan kunit testcases Yeoreum Yun
2025-09-03 12:49 ` Andrey Konovalov [this message]
2025-09-04 7:45 ` Yeoreum Yun
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CA+fCnZeyKuet2XY9=jOdiK4Z6f4_=Xb5ZBzBaDL-2gFPv9yJ5A@mail.gmail.com' \
--to=andreyknvl@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=ardb@kernel.org \
--cc=broonie@kernel.org \
--cc=catalin.marinas@arm.com \
--cc=corbet@lwn.net \
--cc=david@redhat.com \
--cc=dvyukov@google.com \
--cc=glider@google.com \
--cc=hardevsinh.palaniya@siliconsignals.io \
--cc=james.morse@arm.com \
--cc=jhubbard@nvidia.com \
--cc=kaleshsingh@google.com \
--cc=kasan-dev@googlegroups.com \
--cc=leitao@debian.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=maz@kernel.org \
--cc=oliver.upton@linux.dev \
--cc=pankaj.gupta@amd.com \
--cc=ryabinin.a.a@gmail.com \
--cc=scott@os.amperecomputing.com \
--cc=vincenzo.frascino@arm.com \
--cc=will@kernel.org \
--cc=workflows@vger.kernel.org \
--cc=yang@os.amperecomputing.com \
--cc=yeoreum.yun@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).