Commit 4e76c8cc authored by Paul Heidekrüger's avatar Paul Heidekrüger Committed by Andrew Morton

kasan: add atomic tests

Test that KASan can detect some unsafe atomic accesses.

As discussed in the linked thread below, these tests attempt to cover
the most common uses of atomics and, therefore, aren't exhaustive.

Link: https://lkml.kernel.org/r/20240202113259.3045705-1-paul.heidekrueger@tum.de
Link: https://lore.kernel.org/all/20240131210041.686657-1-paul.heidekrueger@tum.de/T/#uSigned-off-by: default avatarPaul Heidekrüger <paul.heidekrueger@tum.de>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=214055Acked-by: default avatarMark Rutland <mark.rutland@arm.com>
Cc: Marco Elver <elver@google.com>
Cc: Andrey Konovalov <andreyknvl@gmail.com>
Cc: Alexander Potapenko <glider@google.com>
Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 09dacb78
......@@ -697,6 +697,84 @@ static void kmalloc_uaf3(struct kunit *test)
KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr1)[8]);
}
static void kasan_atomics_helper(struct kunit *test, void *unsafe, void *safe)
{
int *i_unsafe = (int *)unsafe;
KUNIT_EXPECT_KASAN_FAIL(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(test, smp_store_release(i_unsafe, 42));
KUNIT_EXPECT_KASAN_FAIL(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));
KUNIT_EXPECT_KASAN_FAIL(test, atomic_inc(unsafe));
KUNIT_EXPECT_KASAN_FAIL(test, atomic_dec(unsafe));
KUNIT_EXPECT_KASAN_FAIL(test, atomic_and(42, unsafe));
KUNIT_EXPECT_KASAN_FAIL(test, atomic_andnot(42, unsafe));
KUNIT_EXPECT_KASAN_FAIL(test, atomic_or(42, unsafe));
KUNIT_EXPECT_KASAN_FAIL(test, atomic_xor(42, unsafe));
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));
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));
KUNIT_EXPECT_KASAN_FAIL(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));
KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_inc(unsafe));
KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_dec(unsafe));
KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_and(42, unsafe));
KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_andnot(42, unsafe));
KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_or(42, unsafe));
KUNIT_EXPECT_KASAN_FAIL(test, atomic_long_xor(42, unsafe));
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));
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));
}
static void kasan_atomics(struct kunit *test)
{
void *a1, *a2;
/*
* Just as with kasan_bitops_tags(), we allocate 48 bytes of memory such
* that the following 16 bytes will make up the redzone.
*/
a1 = kzalloc(48, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, a1);
a2 = kzalloc(sizeof(int), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, a1);
/* Use atomics to access the redzone. */
kasan_atomics_helper(test, a1 + 48, a2);
kfree(a1);
kfree(a2);
}
static void kmalloc_double_kzfree(struct kunit *test)
{
char *ptr;
......@@ -1883,6 +1961,7 @@ static struct kunit_case kasan_kunit_test_cases[] = {
KUNIT_CASE(kasan_strings),
KUNIT_CASE(kasan_bitops_generic),
KUNIT_CASE(kasan_bitops_tags),
KUNIT_CASE(kasan_atomics),
KUNIT_CASE(vmalloc_helpers_tags),
KUNIT_CASE(vmalloc_oob),
KUNIT_CASE(vmap_tags),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment