162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (c) 2014 Samsung Electronics Co., Ltd.
562306a36Sopenharmony_ci * Author: Andrey Ryabinin <a.ryabinin@samsung.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt) "kasan_test: " fmt
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <kunit/test.h>
1162306a36Sopenharmony_ci#include <linux/bitops.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/io.h>
1462306a36Sopenharmony_ci#include <linux/kasan.h>
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/mm.h>
1762306a36Sopenharmony_ci#include <linux/mman.h>
1862306a36Sopenharmony_ci#include <linux/module.h>
1962306a36Sopenharmony_ci#include <linux/printk.h>
2062306a36Sopenharmony_ci#include <linux/random.h>
2162306a36Sopenharmony_ci#include <linux/set_memory.h>
2262306a36Sopenharmony_ci#include <linux/slab.h>
2362306a36Sopenharmony_ci#include <linux/string.h>
2462306a36Sopenharmony_ci#include <linux/tracepoint.h>
2562306a36Sopenharmony_ci#include <linux/uaccess.h>
2662306a36Sopenharmony_ci#include <linux/vmalloc.h>
2762306a36Sopenharmony_ci#include <trace/events/printk.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <asm/page.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include "kasan.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define OOB_TAG_OFF (IS_ENABLED(CONFIG_KASAN_GENERIC) ? 0 : KASAN_GRANULE_SIZE)
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic bool multishot;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* Fields set based on lines observed in the console. */
3862306a36Sopenharmony_cistatic struct {
3962306a36Sopenharmony_ci	bool report_found;
4062306a36Sopenharmony_ci	bool async_fault;
4162306a36Sopenharmony_ci} test_status;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/*
4462306a36Sopenharmony_ci * Some tests use these global variables to store return values from function
4562306a36Sopenharmony_ci * calls that could otherwise be eliminated by the compiler as dead code.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_civoid *kasan_ptr_result;
4862306a36Sopenharmony_ciint kasan_int_result;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/* Probe for console output: obtains test_status lines of interest. */
5162306a36Sopenharmony_cistatic void probe_console(void *ignore, const char *buf, size_t len)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	if (strnstr(buf, "BUG: KASAN: ", len))
5462306a36Sopenharmony_ci		WRITE_ONCE(test_status.report_found, true);
5562306a36Sopenharmony_ci	else if (strnstr(buf, "Asynchronous fault: ", len))
5662306a36Sopenharmony_ci		WRITE_ONCE(test_status.async_fault, true);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic int kasan_suite_init(struct kunit_suite *suite)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	if (!kasan_enabled()) {
6262306a36Sopenharmony_ci		pr_err("Can't run KASAN tests with KASAN disabled");
6362306a36Sopenharmony_ci		return -1;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/* Stop failing KUnit tests on KASAN reports. */
6762306a36Sopenharmony_ci	kasan_kunit_test_suite_start();
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/*
7062306a36Sopenharmony_ci	 * Temporarily enable multi-shot mode. Otherwise, KASAN would only
7162306a36Sopenharmony_ci	 * report the first detected bug and panic the kernel if panic_on_warn
7262306a36Sopenharmony_ci	 * is enabled.
7362306a36Sopenharmony_ci	 */
7462306a36Sopenharmony_ci	multishot = kasan_save_enable_multi_shot();
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	register_trace_console(probe_console, NULL);
7762306a36Sopenharmony_ci	return 0;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic void kasan_suite_exit(struct kunit_suite *suite)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	kasan_kunit_test_suite_end();
8362306a36Sopenharmony_ci	kasan_restore_multi_shot(multishot);
8462306a36Sopenharmony_ci	unregister_trace_console(probe_console, NULL);
8562306a36Sopenharmony_ci	tracepoint_synchronize_unregister();
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic void kasan_test_exit(struct kunit *test)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE(test, READ_ONCE(test_status.report_found));
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/**
9462306a36Sopenharmony_ci * KUNIT_EXPECT_KASAN_FAIL() - check that the executed expression produces a
9562306a36Sopenharmony_ci * KASAN report; causes a test failure otherwise. This relies on a KUnit
9662306a36Sopenharmony_ci * resource named "kasan_status". Do not use this name for KUnit resources
9762306a36Sopenharmony_ci * outside of KASAN tests.
9862306a36Sopenharmony_ci *
9962306a36Sopenharmony_ci * For hardware tag-based KASAN, when a synchronous tag fault happens, tag
10062306a36Sopenharmony_ci * checking is auto-disabled. When this happens, this test handler reenables
10162306a36Sopenharmony_ci * tag checking. As tag checking can be only disabled or enabled per CPU,
10262306a36Sopenharmony_ci * this handler disables migration (preemption).
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci * Since the compiler doesn't see that the expression can change the test_status
10562306a36Sopenharmony_ci * fields, it can reorder or optimize away the accesses to those fields.
10662306a36Sopenharmony_ci * Use READ/WRITE_ONCE() for the accesses and compiler barriers around the
10762306a36Sopenharmony_ci * expression to prevent that.
10862306a36Sopenharmony_ci *
10962306a36Sopenharmony_ci * In between KUNIT_EXPECT_KASAN_FAIL checks, test_status.report_found is kept
11062306a36Sopenharmony_ci * as false. This allows detecting KASAN reports that happen outside of the
11162306a36Sopenharmony_ci * checks by asserting !test_status.report_found at the start of
11262306a36Sopenharmony_ci * KUNIT_EXPECT_KASAN_FAIL and in kasan_test_exit.
11362306a36Sopenharmony_ci */
11462306a36Sopenharmony_ci#define KUNIT_EXPECT_KASAN_FAIL(test, expression) do {			\
11562306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_KASAN_HW_TAGS) &&				\
11662306a36Sopenharmony_ci	    kasan_sync_fault_possible())				\
11762306a36Sopenharmony_ci		migrate_disable();					\
11862306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE(test, READ_ONCE(test_status.report_found));	\
11962306a36Sopenharmony_ci	barrier();							\
12062306a36Sopenharmony_ci	expression;							\
12162306a36Sopenharmony_ci	barrier();							\
12262306a36Sopenharmony_ci	if (kasan_async_fault_possible())				\
12362306a36Sopenharmony_ci		kasan_force_async_fault();				\
12462306a36Sopenharmony_ci	if (!READ_ONCE(test_status.report_found)) {			\
12562306a36Sopenharmony_ci		KUNIT_FAIL(test, KUNIT_SUBTEST_INDENT "KASAN failure "	\
12662306a36Sopenharmony_ci				"expected in \"" #expression		\
12762306a36Sopenharmony_ci				 "\", but none occurred");		\
12862306a36Sopenharmony_ci	}								\
12962306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_KASAN_HW_TAGS) &&				\
13062306a36Sopenharmony_ci	    kasan_sync_fault_possible()) {				\
13162306a36Sopenharmony_ci		if (READ_ONCE(test_status.report_found) &&		\
13262306a36Sopenharmony_ci		    !READ_ONCE(test_status.async_fault))		\
13362306a36Sopenharmony_ci			kasan_enable_hw_tags();				\
13462306a36Sopenharmony_ci		migrate_enable();					\
13562306a36Sopenharmony_ci	}								\
13662306a36Sopenharmony_ci	WRITE_ONCE(test_status.report_found, false);			\
13762306a36Sopenharmony_ci	WRITE_ONCE(test_status.async_fault, false);			\
13862306a36Sopenharmony_ci} while (0)
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci#define KASAN_TEST_NEEDS_CONFIG_ON(test, config) do {			\
14162306a36Sopenharmony_ci	if (!IS_ENABLED(config))					\
14262306a36Sopenharmony_ci		kunit_skip((test), "Test requires " #config "=y");	\
14362306a36Sopenharmony_ci} while (0)
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#define KASAN_TEST_NEEDS_CONFIG_OFF(test, config) do {			\
14662306a36Sopenharmony_ci	if (IS_ENABLED(config))						\
14762306a36Sopenharmony_ci		kunit_skip((test), "Test requires " #config "=n");	\
14862306a36Sopenharmony_ci} while (0)
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci#define KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test) do {		\
15162306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_KASAN_HW_TAGS))				\
15262306a36Sopenharmony_ci		break;  /* No compiler instrumentation. */		\
15362306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX))	\
15462306a36Sopenharmony_ci		break;  /* Should always be instrumented! */		\
15562306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_GENERIC_ENTRY))				\
15662306a36Sopenharmony_ci		kunit_skip((test), "Test requires checked mem*()");	\
15762306a36Sopenharmony_ci} while (0)
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic void kmalloc_oob_right(struct kunit *test)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	char *ptr;
16262306a36Sopenharmony_ci	size_t size = 128 - KASAN_GRANULE_SIZE - 5;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
16562306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr);
16862306a36Sopenharmony_ci	/*
16962306a36Sopenharmony_ci	 * An unaligned access past the requested kmalloc size.
17062306a36Sopenharmony_ci	 * Only generic KASAN can precisely detect these.
17162306a36Sopenharmony_ci	 */
17262306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_KASAN_GENERIC))
17362306a36Sopenharmony_ci		KUNIT_EXPECT_KASAN_FAIL(test, ptr[size] = 'x');
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	/*
17662306a36Sopenharmony_ci	 * An aligned access into the first out-of-bounds granule that falls
17762306a36Sopenharmony_ci	 * within the aligned kmalloc object.
17862306a36Sopenharmony_ci	 */
17962306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ptr[size + 5] = 'y');
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	/* Out-of-bounds access past the aligned kmalloc object. */
18262306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ptr[0] =
18362306a36Sopenharmony_ci					ptr[size + KASAN_GRANULE_SIZE + 5]);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	kfree(ptr);
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic void kmalloc_oob_left(struct kunit *test)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	char *ptr;
19162306a36Sopenharmony_ci	size_t size = 15;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
19462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr);
19762306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, *ptr = *(ptr - 1));
19862306a36Sopenharmony_ci	kfree(ptr);
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic void kmalloc_node_oob_right(struct kunit *test)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	char *ptr;
20462306a36Sopenharmony_ci	size_t size = 4096;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	ptr = kmalloc_node(size, GFP_KERNEL, 0);
20762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr);
21062306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ptr[0] = ptr[size]);
21162306a36Sopenharmony_ci	kfree(ptr);
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/*
21562306a36Sopenharmony_ci * These kmalloc_pagealloc_* tests try allocating a memory chunk that doesn't
21662306a36Sopenharmony_ci * fit into a slab cache and therefore is allocated via the page allocator
21762306a36Sopenharmony_ci * fallback. Since this kind of fallback is only implemented for SLUB, these
21862306a36Sopenharmony_ci * tests are limited to that allocator.
21962306a36Sopenharmony_ci */
22062306a36Sopenharmony_cistatic void kmalloc_pagealloc_oob_right(struct kunit *test)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	char *ptr;
22362306a36Sopenharmony_ci	size_t size = KMALLOC_MAX_CACHE_SIZE + 10;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_SLUB);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
22862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr);
23162306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ptr[size + OOB_TAG_OFF] = 0);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	kfree(ptr);
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic void kmalloc_pagealloc_uaf(struct kunit *test)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	char *ptr;
23962306a36Sopenharmony_ci	size_t size = KMALLOC_MAX_CACHE_SIZE + 10;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_SLUB);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
24462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
24562306a36Sopenharmony_ci	kfree(ptr);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[0]);
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic void kmalloc_pagealloc_invalid_free(struct kunit *test)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	char *ptr;
25362306a36Sopenharmony_ci	size_t size = KMALLOC_MAX_CACHE_SIZE + 10;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_SLUB);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
25862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, kfree(ptr + 1));
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic void pagealloc_oob_right(struct kunit *test)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	char *ptr;
26662306a36Sopenharmony_ci	struct page *pages;
26762306a36Sopenharmony_ci	size_t order = 4;
26862306a36Sopenharmony_ci	size_t size = (1UL << (PAGE_SHIFT + order));
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	/*
27162306a36Sopenharmony_ci	 * With generic KASAN page allocations have no redzones, thus
27262306a36Sopenharmony_ci	 * out-of-bounds detection is not guaranteed.
27362306a36Sopenharmony_ci	 * See https://bugzilla.kernel.org/show_bug.cgi?id=210503.
27462306a36Sopenharmony_ci	 */
27562306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	pages = alloc_pages(GFP_KERNEL, order);
27862306a36Sopenharmony_ci	ptr = page_address(pages);
27962306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ptr[0] = ptr[size]);
28262306a36Sopenharmony_ci	free_pages((unsigned long)ptr, order);
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic void pagealloc_uaf(struct kunit *test)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	char *ptr;
28862306a36Sopenharmony_ci	struct page *pages;
28962306a36Sopenharmony_ci	size_t order = 4;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	pages = alloc_pages(GFP_KERNEL, order);
29262306a36Sopenharmony_ci	ptr = page_address(pages);
29362306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
29462306a36Sopenharmony_ci	free_pages((unsigned long)ptr, order);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[0]);
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic void kmalloc_large_oob_right(struct kunit *test)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	char *ptr;
30262306a36Sopenharmony_ci	size_t size = KMALLOC_MAX_CACHE_SIZE - 256;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	/*
30562306a36Sopenharmony_ci	 * Allocate a chunk that is large enough, but still fits into a slab
30662306a36Sopenharmony_ci	 * and does not trigger the page allocator fallback in SLUB.
30762306a36Sopenharmony_ci	 */
30862306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
30962306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr);
31262306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ptr[size] = 0);
31362306a36Sopenharmony_ci	kfree(ptr);
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic void krealloc_more_oob_helper(struct kunit *test,
31762306a36Sopenharmony_ci					size_t size1, size_t size2)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	char *ptr1, *ptr2;
32062306a36Sopenharmony_ci	size_t middle;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	KUNIT_ASSERT_LT(test, size1, size2);
32362306a36Sopenharmony_ci	middle = size1 + (size2 - size1) / 2;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	ptr1 = kmalloc(size1, GFP_KERNEL);
32662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr1);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	ptr2 = krealloc(ptr1, size2, GFP_KERNEL);
32962306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr2);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/* Suppress -Warray-bounds warnings. */
33262306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr2);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	/* All offsets up to size2 must be accessible. */
33562306a36Sopenharmony_ci	ptr2[size1 - 1] = 'x';
33662306a36Sopenharmony_ci	ptr2[size1] = 'x';
33762306a36Sopenharmony_ci	ptr2[middle] = 'x';
33862306a36Sopenharmony_ci	ptr2[size2 - 1] = 'x';
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* Generic mode is precise, so unaligned size2 must be inaccessible. */
34162306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_KASAN_GENERIC))
34262306a36Sopenharmony_ci		KUNIT_EXPECT_KASAN_FAIL(test, ptr2[size2] = 'x');
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/* For all modes first aligned offset after size2 must be inaccessible. */
34562306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test,
34662306a36Sopenharmony_ci		ptr2[round_up(size2, KASAN_GRANULE_SIZE)] = 'x');
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	kfree(ptr2);
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic void krealloc_less_oob_helper(struct kunit *test,
35262306a36Sopenharmony_ci					size_t size1, size_t size2)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	char *ptr1, *ptr2;
35562306a36Sopenharmony_ci	size_t middle;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	KUNIT_ASSERT_LT(test, size2, size1);
35862306a36Sopenharmony_ci	middle = size2 + (size1 - size2) / 2;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	ptr1 = kmalloc(size1, GFP_KERNEL);
36162306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr1);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	ptr2 = krealloc(ptr1, size2, GFP_KERNEL);
36462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr2);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* Suppress -Warray-bounds warnings. */
36762306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr2);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	/* Must be accessible for all modes. */
37062306a36Sopenharmony_ci	ptr2[size2 - 1] = 'x';
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/* Generic mode is precise, so unaligned size2 must be inaccessible. */
37362306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_KASAN_GENERIC))
37462306a36Sopenharmony_ci		KUNIT_EXPECT_KASAN_FAIL(test, ptr2[size2] = 'x');
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	/* For all modes first aligned offset after size2 must be inaccessible. */
37762306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test,
37862306a36Sopenharmony_ci		ptr2[round_up(size2, KASAN_GRANULE_SIZE)] = 'x');
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	/*
38162306a36Sopenharmony_ci	 * For all modes all size2, middle, and size1 should land in separate
38262306a36Sopenharmony_ci	 * granules and thus the latter two offsets should be inaccessible.
38362306a36Sopenharmony_ci	 */
38462306a36Sopenharmony_ci	KUNIT_EXPECT_LE(test, round_up(size2, KASAN_GRANULE_SIZE),
38562306a36Sopenharmony_ci				round_down(middle, KASAN_GRANULE_SIZE));
38662306a36Sopenharmony_ci	KUNIT_EXPECT_LE(test, round_up(middle, KASAN_GRANULE_SIZE),
38762306a36Sopenharmony_ci				round_down(size1, KASAN_GRANULE_SIZE));
38862306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ptr2[middle] = 'x');
38962306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ptr2[size1 - 1] = 'x');
39062306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ptr2[size1] = 'x');
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	kfree(ptr2);
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic void krealloc_more_oob(struct kunit *test)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	krealloc_more_oob_helper(test, 201, 235);
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic void krealloc_less_oob(struct kunit *test)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	krealloc_less_oob_helper(test, 235, 201);
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic void krealloc_pagealloc_more_oob(struct kunit *test)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	/* page_alloc fallback in only implemented for SLUB. */
40862306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_SLUB);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	krealloc_more_oob_helper(test, KMALLOC_MAX_CACHE_SIZE + 201,
41162306a36Sopenharmony_ci					KMALLOC_MAX_CACHE_SIZE + 235);
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic void krealloc_pagealloc_less_oob(struct kunit *test)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	/* page_alloc fallback in only implemented for SLUB. */
41762306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_SLUB);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	krealloc_less_oob_helper(test, KMALLOC_MAX_CACHE_SIZE + 235,
42062306a36Sopenharmony_ci					KMALLOC_MAX_CACHE_SIZE + 201);
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci/*
42462306a36Sopenharmony_ci * Check that krealloc() detects a use-after-free, returns NULL,
42562306a36Sopenharmony_ci * and doesn't unpoison the freed object.
42662306a36Sopenharmony_ci */
42762306a36Sopenharmony_cistatic void krealloc_uaf(struct kunit *test)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	char *ptr1, *ptr2;
43062306a36Sopenharmony_ci	int size1 = 201;
43162306a36Sopenharmony_ci	int size2 = 235;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	ptr1 = kmalloc(size1, GFP_KERNEL);
43462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr1);
43562306a36Sopenharmony_ci	kfree(ptr1);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ptr2 = krealloc(ptr1, size2, GFP_KERNEL));
43862306a36Sopenharmony_ci	KUNIT_ASSERT_NULL(test, ptr2);
43962306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, *(volatile char *)ptr1);
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic void kmalloc_oob_16(struct kunit *test)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	struct {
44562306a36Sopenharmony_ci		u64 words[2];
44662306a36Sopenharmony_ci	} *ptr1, *ptr2;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	/* This test is specifically crafted for the generic mode. */
45162306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_GENERIC);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	/* RELOC_HIDE to prevent gcc from warning about short alloc */
45462306a36Sopenharmony_ci	ptr1 = RELOC_HIDE(kmalloc(sizeof(*ptr1) - 3, GFP_KERNEL), 0);
45562306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr1);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	ptr2 = kmalloc(sizeof(*ptr2), GFP_KERNEL);
45862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr2);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr1);
46162306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr2);
46262306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, *ptr1 = *ptr2);
46362306a36Sopenharmony_ci	kfree(ptr1);
46462306a36Sopenharmony_ci	kfree(ptr2);
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic void kmalloc_uaf_16(struct kunit *test)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct {
47062306a36Sopenharmony_ci		u64 words[2];
47162306a36Sopenharmony_ci	} *ptr1, *ptr2;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	ptr1 = kmalloc(sizeof(*ptr1), GFP_KERNEL);
47662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr1);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	ptr2 = kmalloc(sizeof(*ptr2), GFP_KERNEL);
47962306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr2);
48062306a36Sopenharmony_ci	kfree(ptr2);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, *ptr1 = *ptr2);
48362306a36Sopenharmony_ci	kfree(ptr1);
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci/*
48762306a36Sopenharmony_ci * Note: in the memset tests below, the written range touches both valid and
48862306a36Sopenharmony_ci * invalid memory. This makes sure that the instrumentation does not only check
48962306a36Sopenharmony_ci * the starting address but the whole range.
49062306a36Sopenharmony_ci */
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic void kmalloc_oob_memset_2(struct kunit *test)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	char *ptr;
49562306a36Sopenharmony_ci	size_t size = 128 - KASAN_GRANULE_SIZE;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
50062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(size);
50362306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, memset(ptr + size - 1, 0, 2));
50462306a36Sopenharmony_ci	kfree(ptr);
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic void kmalloc_oob_memset_4(struct kunit *test)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci	char *ptr;
51062306a36Sopenharmony_ci	size_t size = 128 - KASAN_GRANULE_SIZE;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
51562306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(size);
51862306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, memset(ptr + size - 3, 0, 4));
51962306a36Sopenharmony_ci	kfree(ptr);
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic void kmalloc_oob_memset_8(struct kunit *test)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	char *ptr;
52562306a36Sopenharmony_ci	size_t size = 128 - KASAN_GRANULE_SIZE;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
53062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(size);
53362306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, memset(ptr + size - 7, 0, 8));
53462306a36Sopenharmony_ci	kfree(ptr);
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic void kmalloc_oob_memset_16(struct kunit *test)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	char *ptr;
54062306a36Sopenharmony_ci	size_t size = 128 - KASAN_GRANULE_SIZE;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
54562306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(size);
54862306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, memset(ptr + size - 15, 0, 16));
54962306a36Sopenharmony_ci	kfree(ptr);
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistatic void kmalloc_oob_in_memset(struct kunit *test)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	char *ptr;
55562306a36Sopenharmony_ci	size_t size = 128 - KASAN_GRANULE_SIZE;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
56062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr);
56362306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(size);
56462306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test,
56562306a36Sopenharmony_ci				memset(ptr, 0, size + KASAN_GRANULE_SIZE));
56662306a36Sopenharmony_ci	kfree(ptr);
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic void kmalloc_memmove_negative_size(struct kunit *test)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	char *ptr;
57262306a36Sopenharmony_ci	size_t size = 64;
57362306a36Sopenharmony_ci	size_t invalid_size = -2;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	/*
57862306a36Sopenharmony_ci	 * Hardware tag-based mode doesn't check memmove for negative size.
57962306a36Sopenharmony_ci	 * As a result, this test introduces a side-effect memory corruption,
58062306a36Sopenharmony_ci	 * which can result in a crash.
58162306a36Sopenharmony_ci	 */
58262306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_HW_TAGS);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
58562306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	memset((char *)ptr, 0, 64);
58862306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr);
58962306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(invalid_size);
59062306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test,
59162306a36Sopenharmony_ci		memmove((char *)ptr, (char *)ptr + 4, invalid_size));
59262306a36Sopenharmony_ci	kfree(ptr);
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cistatic void kmalloc_memmove_invalid_size(struct kunit *test)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	char *ptr;
59862306a36Sopenharmony_ci	size_t size = 64;
59962306a36Sopenharmony_ci	size_t invalid_size = size;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
60462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	memset((char *)ptr, 0, 64);
60762306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr);
60862306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(invalid_size);
60962306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test,
61062306a36Sopenharmony_ci		memmove((char *)ptr, (char *)ptr + 4, invalid_size));
61162306a36Sopenharmony_ci	kfree(ptr);
61262306a36Sopenharmony_ci}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_cistatic void kmalloc_uaf(struct kunit *test)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	char *ptr;
61762306a36Sopenharmony_ci	size_t size = 10;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
62062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	kfree(ptr);
62362306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[8]);
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cistatic void kmalloc_uaf_memset(struct kunit *test)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	char *ptr;
62962306a36Sopenharmony_ci	size_t size = 33;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	/*
63462306a36Sopenharmony_ci	 * Only generic KASAN uses quarantine, which is required to avoid a
63562306a36Sopenharmony_ci	 * kernel memory corruption this test causes.
63662306a36Sopenharmony_ci	 */
63762306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_GENERIC);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
64062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	kfree(ptr);
64362306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, memset(ptr, 0, size));
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cistatic void kmalloc_uaf2(struct kunit *test)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	char *ptr1, *ptr2;
64962306a36Sopenharmony_ci	size_t size = 43;
65062306a36Sopenharmony_ci	int counter = 0;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ciagain:
65362306a36Sopenharmony_ci	ptr1 = kmalloc(size, GFP_KERNEL);
65462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr1);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	kfree(ptr1);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	ptr2 = kmalloc(size, GFP_KERNEL);
65962306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr2);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	/*
66262306a36Sopenharmony_ci	 * For tag-based KASAN ptr1 and ptr2 tags might happen to be the same.
66362306a36Sopenharmony_ci	 * Allow up to 16 attempts at generating different tags.
66462306a36Sopenharmony_ci	 */
66562306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_KASAN_GENERIC) && ptr1 == ptr2 && counter++ < 16) {
66662306a36Sopenharmony_ci		kfree(ptr2);
66762306a36Sopenharmony_ci		goto again;
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr1)[40]);
67162306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_NE(test, ptr1, ptr2);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	kfree(ptr2);
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci/*
67762306a36Sopenharmony_ci * Check that KASAN detects use-after-free when another object was allocated in
67862306a36Sopenharmony_ci * the same slot. Relevant for the tag-based modes, which do not use quarantine.
67962306a36Sopenharmony_ci */
68062306a36Sopenharmony_cistatic void kmalloc_uaf3(struct kunit *test)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	char *ptr1, *ptr2;
68362306a36Sopenharmony_ci	size_t size = 100;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	/* This test is specifically crafted for tag-based modes. */
68662306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	ptr1 = kmalloc(size, GFP_KERNEL);
68962306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr1);
69062306a36Sopenharmony_ci	kfree(ptr1);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	ptr2 = kmalloc(size, GFP_KERNEL);
69362306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr2);
69462306a36Sopenharmony_ci	kfree(ptr2);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr1)[8]);
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_cistatic void kfree_via_page(struct kunit *test)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	char *ptr;
70262306a36Sopenharmony_ci	size_t size = 8;
70362306a36Sopenharmony_ci	struct page *page;
70462306a36Sopenharmony_ci	unsigned long offset;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
70762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	page = virt_to_page(ptr);
71062306a36Sopenharmony_ci	offset = offset_in_page(ptr);
71162306a36Sopenharmony_ci	kfree(page_address(page) + offset);
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_cistatic void kfree_via_phys(struct kunit *test)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	char *ptr;
71762306a36Sopenharmony_ci	size_t size = 8;
71862306a36Sopenharmony_ci	phys_addr_t phys;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
72162306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	phys = virt_to_phys(ptr);
72462306a36Sopenharmony_ci	kfree(phys_to_virt(phys));
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_cistatic void kmem_cache_oob(struct kunit *test)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	char *p;
73062306a36Sopenharmony_ci	size_t size = 200;
73162306a36Sopenharmony_ci	struct kmem_cache *cache;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	cache = kmem_cache_create("test_cache", size, 0, 0, NULL);
73462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cache);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	p = kmem_cache_alloc(cache, GFP_KERNEL);
73762306a36Sopenharmony_ci	if (!p) {
73862306a36Sopenharmony_ci		kunit_err(test, "Allocation failed: %s\n", __func__);
73962306a36Sopenharmony_ci		kmem_cache_destroy(cache);
74062306a36Sopenharmony_ci		return;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, *p = p[size + OOB_TAG_OFF]);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	kmem_cache_free(cache, p);
74662306a36Sopenharmony_ci	kmem_cache_destroy(cache);
74762306a36Sopenharmony_ci}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_cistatic void kmem_cache_accounted(struct kunit *test)
75062306a36Sopenharmony_ci{
75162306a36Sopenharmony_ci	int i;
75262306a36Sopenharmony_ci	char *p;
75362306a36Sopenharmony_ci	size_t size = 200;
75462306a36Sopenharmony_ci	struct kmem_cache *cache;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	cache = kmem_cache_create("test_cache", size, 0, SLAB_ACCOUNT, NULL);
75762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cache);
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	/*
76062306a36Sopenharmony_ci	 * Several allocations with a delay to allow for lazy per memcg kmem
76162306a36Sopenharmony_ci	 * cache creation.
76262306a36Sopenharmony_ci	 */
76362306a36Sopenharmony_ci	for (i = 0; i < 5; i++) {
76462306a36Sopenharmony_ci		p = kmem_cache_alloc(cache, GFP_KERNEL);
76562306a36Sopenharmony_ci		if (!p)
76662306a36Sopenharmony_ci			goto free_cache;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci		kmem_cache_free(cache, p);
76962306a36Sopenharmony_ci		msleep(100);
77062306a36Sopenharmony_ci	}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_cifree_cache:
77362306a36Sopenharmony_ci	kmem_cache_destroy(cache);
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_cistatic void kmem_cache_bulk(struct kunit *test)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	struct kmem_cache *cache;
77962306a36Sopenharmony_ci	size_t size = 200;
78062306a36Sopenharmony_ci	char *p[10];
78162306a36Sopenharmony_ci	bool ret;
78262306a36Sopenharmony_ci	int i;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	cache = kmem_cache_create("test_cache", size, 0, 0, NULL);
78562306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cache);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	ret = kmem_cache_alloc_bulk(cache, GFP_KERNEL, ARRAY_SIZE(p), (void **)&p);
78862306a36Sopenharmony_ci	if (!ret) {
78962306a36Sopenharmony_ci		kunit_err(test, "Allocation failed: %s\n", __func__);
79062306a36Sopenharmony_ci		kmem_cache_destroy(cache);
79162306a36Sopenharmony_ci		return;
79262306a36Sopenharmony_ci	}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p); i++)
79562306a36Sopenharmony_ci		p[i][0] = p[i][size - 1] = 42;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	kmem_cache_free_bulk(cache, ARRAY_SIZE(p), (void **)&p);
79862306a36Sopenharmony_ci	kmem_cache_destroy(cache);
79962306a36Sopenharmony_ci}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cistatic char global_array[10];
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_cistatic void kasan_global_oob_right(struct kunit *test)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	/*
80662306a36Sopenharmony_ci	 * Deliberate out-of-bounds access. To prevent CONFIG_UBSAN_LOCAL_BOUNDS
80762306a36Sopenharmony_ci	 * from failing here and panicking the kernel, access the array via a
80862306a36Sopenharmony_ci	 * volatile pointer, which will prevent the compiler from being able to
80962306a36Sopenharmony_ci	 * determine the array bounds.
81062306a36Sopenharmony_ci	 *
81162306a36Sopenharmony_ci	 * This access uses a volatile pointer to char (char *volatile) rather
81262306a36Sopenharmony_ci	 * than the more conventional pointer to volatile char (volatile char *)
81362306a36Sopenharmony_ci	 * because we want to prevent the compiler from making inferences about
81462306a36Sopenharmony_ci	 * the pointer itself (i.e. its array bounds), not the data that it
81562306a36Sopenharmony_ci	 * refers to.
81662306a36Sopenharmony_ci	 */
81762306a36Sopenharmony_ci	char *volatile array = global_array;
81862306a36Sopenharmony_ci	char *p = &array[ARRAY_SIZE(global_array) + 3];
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	/* Only generic mode instruments globals. */
82162306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_GENERIC);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, *(volatile char *)p);
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cistatic void kasan_global_oob_left(struct kunit *test)
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	char *volatile array = global_array;
82962306a36Sopenharmony_ci	char *p = array - 3;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	/*
83262306a36Sopenharmony_ci	 * GCC is known to fail this test, skip it.
83362306a36Sopenharmony_ci	 * See https://bugzilla.kernel.org/show_bug.cgi?id=215051.
83462306a36Sopenharmony_ci	 */
83562306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_CC_IS_CLANG);
83662306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_GENERIC);
83762306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, *(volatile char *)p);
83862306a36Sopenharmony_ci}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci/* Check that ksize() does NOT unpoison whole object. */
84162306a36Sopenharmony_cistatic void ksize_unpoisons_memory(struct kunit *test)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	char *ptr;
84462306a36Sopenharmony_ci	size_t size = 128 - KASAN_GRANULE_SIZE - 5;
84562306a36Sopenharmony_ci	size_t real_size;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
84862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	real_size = ksize(ptr);
85162306a36Sopenharmony_ci	KUNIT_EXPECT_GT(test, real_size, size);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	/* These accesses shouldn't trigger a KASAN report. */
85662306a36Sopenharmony_ci	ptr[0] = 'x';
85762306a36Sopenharmony_ci	ptr[size - 1] = 'x';
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	/* These must trigger a KASAN report. */
86062306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_KASAN_GENERIC))
86162306a36Sopenharmony_ci		KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[size]);
86262306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[size + 5]);
86362306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[real_size - 1]);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	kfree(ptr);
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci/*
86962306a36Sopenharmony_ci * Check that a use-after-free is detected by ksize() and via normal accesses
87062306a36Sopenharmony_ci * after it.
87162306a36Sopenharmony_ci */
87262306a36Sopenharmony_cistatic void ksize_uaf(struct kunit *test)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	char *ptr;
87562306a36Sopenharmony_ci	int size = 128 - KASAN_GRANULE_SIZE;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
87862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
87962306a36Sopenharmony_ci	kfree(ptr);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr);
88262306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ksize(ptr));
88362306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[0]);
88462306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[size]);
88562306a36Sopenharmony_ci}
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_cistatic void kasan_stack_oob(struct kunit *test)
88862306a36Sopenharmony_ci{
88962306a36Sopenharmony_ci	char stack_array[10];
89062306a36Sopenharmony_ci	/* See comment in kasan_global_oob_right. */
89162306a36Sopenharmony_ci	char *volatile array = stack_array;
89262306a36Sopenharmony_ci	char *p = &array[ARRAY_SIZE(stack_array) + OOB_TAG_OFF];
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_STACK);
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, *(volatile char *)p);
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_cistatic void kasan_alloca_oob_left(struct kunit *test)
90062306a36Sopenharmony_ci{
90162306a36Sopenharmony_ci	volatile int i = 10;
90262306a36Sopenharmony_ci	char alloca_array[i];
90362306a36Sopenharmony_ci	/* See comment in kasan_global_oob_right. */
90462306a36Sopenharmony_ci	char *volatile array = alloca_array;
90562306a36Sopenharmony_ci	char *p = array - 1;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	/* Only generic mode instruments dynamic allocas. */
90862306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_GENERIC);
90962306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_STACK);
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, *(volatile char *)p);
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cistatic void kasan_alloca_oob_right(struct kunit *test)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	volatile int i = 10;
91762306a36Sopenharmony_ci	char alloca_array[i];
91862306a36Sopenharmony_ci	/* See comment in kasan_global_oob_right. */
91962306a36Sopenharmony_ci	char *volatile array = alloca_array;
92062306a36Sopenharmony_ci	char *p = array + i;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	/* Only generic mode instruments dynamic allocas. */
92362306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_GENERIC);
92462306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_STACK);
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, *(volatile char *)p);
92762306a36Sopenharmony_ci}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_cistatic void kmem_cache_double_free(struct kunit *test)
93062306a36Sopenharmony_ci{
93162306a36Sopenharmony_ci	char *p;
93262306a36Sopenharmony_ci	size_t size = 200;
93362306a36Sopenharmony_ci	struct kmem_cache *cache;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	cache = kmem_cache_create("test_cache", size, 0, 0, NULL);
93662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cache);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	p = kmem_cache_alloc(cache, GFP_KERNEL);
93962306a36Sopenharmony_ci	if (!p) {
94062306a36Sopenharmony_ci		kunit_err(test, "Allocation failed: %s\n", __func__);
94162306a36Sopenharmony_ci		kmem_cache_destroy(cache);
94262306a36Sopenharmony_ci		return;
94362306a36Sopenharmony_ci	}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	kmem_cache_free(cache, p);
94662306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, kmem_cache_free(cache, p));
94762306a36Sopenharmony_ci	kmem_cache_destroy(cache);
94862306a36Sopenharmony_ci}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_cistatic void kmem_cache_invalid_free(struct kunit *test)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	char *p;
95362306a36Sopenharmony_ci	size_t size = 200;
95462306a36Sopenharmony_ci	struct kmem_cache *cache;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	cache = kmem_cache_create("test_cache", size, 0, SLAB_TYPESAFE_BY_RCU,
95762306a36Sopenharmony_ci				  NULL);
95862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cache);
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	p = kmem_cache_alloc(cache, GFP_KERNEL);
96162306a36Sopenharmony_ci	if (!p) {
96262306a36Sopenharmony_ci		kunit_err(test, "Allocation failed: %s\n", __func__);
96362306a36Sopenharmony_ci		kmem_cache_destroy(cache);
96462306a36Sopenharmony_ci		return;
96562306a36Sopenharmony_ci	}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	/* Trigger invalid free, the object doesn't get freed. */
96862306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, kmem_cache_free(cache, p + 1));
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	/*
97162306a36Sopenharmony_ci	 * Properly free the object to prevent the "Objects remaining in
97262306a36Sopenharmony_ci	 * test_cache on __kmem_cache_shutdown" BUG failure.
97362306a36Sopenharmony_ci	 */
97462306a36Sopenharmony_ci	kmem_cache_free(cache, p);
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	kmem_cache_destroy(cache);
97762306a36Sopenharmony_ci}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_cistatic void empty_cache_ctor(void *object) { }
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cistatic void kmem_cache_double_destroy(struct kunit *test)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	struct kmem_cache *cache;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	/* Provide a constructor to prevent cache merging. */
98662306a36Sopenharmony_ci	cache = kmem_cache_create("test_cache", 200, 0, 0, empty_cache_ctor);
98762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cache);
98862306a36Sopenharmony_ci	kmem_cache_destroy(cache);
98962306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, kmem_cache_destroy(cache));
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic void kasan_memchr(struct kunit *test)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci	char *ptr;
99562306a36Sopenharmony_ci	size_t size = 24;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	/*
99862306a36Sopenharmony_ci	 * str* functions are not instrumented with CONFIG_AMD_MEM_ENCRYPT.
99962306a36Sopenharmony_ci	 * See https://bugzilla.kernel.org/show_bug.cgi?id=206337 for details.
100062306a36Sopenharmony_ci	 */
100162306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_AMD_MEM_ENCRYPT);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	if (OOB_TAG_OFF)
100462306a36Sopenharmony_ci		size = round_up(size, OOB_TAG_OFF);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL | __GFP_ZERO);
100762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr);
101062306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(size);
101162306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test,
101262306a36Sopenharmony_ci		kasan_ptr_result = memchr(ptr, '1', size + 1));
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	kfree(ptr);
101562306a36Sopenharmony_ci}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_cistatic void kasan_memcmp(struct kunit *test)
101862306a36Sopenharmony_ci{
101962306a36Sopenharmony_ci	char *ptr;
102062306a36Sopenharmony_ci	size_t size = 24;
102162306a36Sopenharmony_ci	int arr[9];
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	/*
102462306a36Sopenharmony_ci	 * str* functions are not instrumented with CONFIG_AMD_MEM_ENCRYPT.
102562306a36Sopenharmony_ci	 * See https://bugzilla.kernel.org/show_bug.cgi?id=206337 for details.
102662306a36Sopenharmony_ci	 */
102762306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_AMD_MEM_ENCRYPT);
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	if (OOB_TAG_OFF)
103062306a36Sopenharmony_ci		size = round_up(size, OOB_TAG_OFF);
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL | __GFP_ZERO);
103362306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
103462306a36Sopenharmony_ci	memset(arr, 0, sizeof(arr));
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(ptr);
103762306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(size);
103862306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test,
103962306a36Sopenharmony_ci		kasan_int_result = memcmp(ptr, arr, size+1));
104062306a36Sopenharmony_ci	kfree(ptr);
104162306a36Sopenharmony_ci}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_cistatic void kasan_strings(struct kunit *test)
104462306a36Sopenharmony_ci{
104562306a36Sopenharmony_ci	char *ptr;
104662306a36Sopenharmony_ci	size_t size = 24;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	/*
104962306a36Sopenharmony_ci	 * str* functions are not instrumented with CONFIG_AMD_MEM_ENCRYPT.
105062306a36Sopenharmony_ci	 * See https://bugzilla.kernel.org/show_bug.cgi?id=206337 for details.
105162306a36Sopenharmony_ci	 */
105262306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_AMD_MEM_ENCRYPT);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL | __GFP_ZERO);
105562306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	kfree(ptr);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	/*
106062306a36Sopenharmony_ci	 * Try to cause only 1 invalid access (less spam in dmesg).
106162306a36Sopenharmony_ci	 * For that we need ptr to point to zeroed byte.
106262306a36Sopenharmony_ci	 * Skip metadata that could be stored in freed object so ptr
106362306a36Sopenharmony_ci	 * will likely point to zeroed byte.
106462306a36Sopenharmony_ci	 */
106562306a36Sopenharmony_ci	ptr += 16;
106662306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, kasan_ptr_result = strchr(ptr, '1'));
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, kasan_ptr_result = strrchr(ptr, '1'));
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, kasan_int_result = strcmp(ptr, "2"));
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, kasan_int_result = strncmp(ptr, "2", 1));
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, kasan_int_result = strlen(ptr));
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, kasan_int_result = strnlen(ptr, 1));
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic void kasan_bitops_modify(struct kunit *test, int nr, void *addr)
108062306a36Sopenharmony_ci{
108162306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, set_bit(nr, addr));
108262306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, __set_bit(nr, addr));
108362306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, clear_bit(nr, addr));
108462306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, __clear_bit(nr, addr));
108562306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, clear_bit_unlock(nr, addr));
108662306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, __clear_bit_unlock(nr, addr));
108762306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, change_bit(nr, addr));
108862306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, __change_bit(nr, addr));
108962306a36Sopenharmony_ci}
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_cistatic void kasan_bitops_test_and_modify(struct kunit *test, int nr, void *addr)
109262306a36Sopenharmony_ci{
109362306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, test_and_set_bit(nr, addr));
109462306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, __test_and_set_bit(nr, addr));
109562306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, test_and_set_bit_lock(nr, addr));
109662306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, test_and_clear_bit(nr, addr));
109762306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, __test_and_clear_bit(nr, addr));
109862306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, test_and_change_bit(nr, addr));
109962306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, __test_and_change_bit(nr, addr));
110062306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, kasan_int_result = test_bit(nr, addr));
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci#if defined(clear_bit_unlock_is_negative_byte)
110362306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, kasan_int_result =
110462306a36Sopenharmony_ci				clear_bit_unlock_is_negative_byte(nr, addr));
110562306a36Sopenharmony_ci#endif
110662306a36Sopenharmony_ci}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_cistatic void kasan_bitops_generic(struct kunit *test)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci	long *bits;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	/* This test is specifically crafted for the generic mode. */
111362306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_GENERIC);
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	/*
111662306a36Sopenharmony_ci	 * Allocate 1 more byte, which causes kzalloc to round up to 16 bytes;
111762306a36Sopenharmony_ci	 * this way we do not actually corrupt other memory.
111862306a36Sopenharmony_ci	 */
111962306a36Sopenharmony_ci	bits = kzalloc(sizeof(*bits) + 1, GFP_KERNEL);
112062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bits);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	/*
112362306a36Sopenharmony_ci	 * Below calls try to access bit within allocated memory; however, the
112462306a36Sopenharmony_ci	 * below accesses are still out-of-bounds, since bitops are defined to
112562306a36Sopenharmony_ci	 * operate on the whole long the bit is in.
112662306a36Sopenharmony_ci	 */
112762306a36Sopenharmony_ci	kasan_bitops_modify(test, BITS_PER_LONG, bits);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	/*
113062306a36Sopenharmony_ci	 * Below calls try to access bit beyond allocated memory.
113162306a36Sopenharmony_ci	 */
113262306a36Sopenharmony_ci	kasan_bitops_test_and_modify(test, BITS_PER_LONG + BITS_PER_BYTE, bits);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	kfree(bits);
113562306a36Sopenharmony_ci}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_cistatic void kasan_bitops_tags(struct kunit *test)
113862306a36Sopenharmony_ci{
113962306a36Sopenharmony_ci	long *bits;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	/* This test is specifically crafted for tag-based modes. */
114262306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC);
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	/* kmalloc-64 cache will be used and the last 16 bytes will be the redzone. */
114562306a36Sopenharmony_ci	bits = kzalloc(48, GFP_KERNEL);
114662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bits);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	/* Do the accesses past the 48 allocated bytes, but within the redone. */
114962306a36Sopenharmony_ci	kasan_bitops_modify(test, BITS_PER_LONG, (void *)bits + 48);
115062306a36Sopenharmony_ci	kasan_bitops_test_and_modify(test, BITS_PER_LONG + BITS_PER_BYTE, (void *)bits + 48);
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	kfree(bits);
115362306a36Sopenharmony_ci}
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_cistatic void kmalloc_double_kzfree(struct kunit *test)
115662306a36Sopenharmony_ci{
115762306a36Sopenharmony_ci	char *ptr;
115862306a36Sopenharmony_ci	size_t size = 16;
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	ptr = kmalloc(size, GFP_KERNEL);
116162306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	kfree_sensitive(ptr);
116462306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, kfree_sensitive(ptr));
116562306a36Sopenharmony_ci}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci/*
116862306a36Sopenharmony_ci * The two tests below check that Generic KASAN prints auxiliary stack traces
116962306a36Sopenharmony_ci * for RCU callbacks and workqueues. The reports need to be inspected manually.
117062306a36Sopenharmony_ci *
117162306a36Sopenharmony_ci * These tests are still enabled for other KASAN modes to make sure that all
117262306a36Sopenharmony_ci * modes report bad accesses in tested scenarios.
117362306a36Sopenharmony_ci */
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_cistatic struct kasan_rcu_info {
117662306a36Sopenharmony_ci	int i;
117762306a36Sopenharmony_ci	struct rcu_head rcu;
117862306a36Sopenharmony_ci} *global_rcu_ptr;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_cistatic void rcu_uaf_reclaim(struct rcu_head *rp)
118162306a36Sopenharmony_ci{
118262306a36Sopenharmony_ci	struct kasan_rcu_info *fp =
118362306a36Sopenharmony_ci		container_of(rp, struct kasan_rcu_info, rcu);
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	kfree(fp);
118662306a36Sopenharmony_ci	((volatile struct kasan_rcu_info *)fp)->i;
118762306a36Sopenharmony_ci}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_cistatic void rcu_uaf(struct kunit *test)
119062306a36Sopenharmony_ci{
119162306a36Sopenharmony_ci	struct kasan_rcu_info *ptr;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	ptr = kmalloc(sizeof(struct kasan_rcu_info), GFP_KERNEL);
119462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	global_rcu_ptr = rcu_dereference_protected(
119762306a36Sopenharmony_ci				(struct kasan_rcu_info __rcu *)ptr, NULL);
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test,
120062306a36Sopenharmony_ci		call_rcu(&global_rcu_ptr->rcu, rcu_uaf_reclaim);
120162306a36Sopenharmony_ci		rcu_barrier());
120262306a36Sopenharmony_ci}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_cistatic void workqueue_uaf_work(struct work_struct *work)
120562306a36Sopenharmony_ci{
120662306a36Sopenharmony_ci	kfree(work);
120762306a36Sopenharmony_ci}
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_cistatic void workqueue_uaf(struct kunit *test)
121062306a36Sopenharmony_ci{
121162306a36Sopenharmony_ci	struct workqueue_struct *workqueue;
121262306a36Sopenharmony_ci	struct work_struct *work;
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	workqueue = create_workqueue("kasan_workqueue_test");
121562306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, workqueue);
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	work = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
121862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, work);
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	INIT_WORK(work, workqueue_uaf_work);
122162306a36Sopenharmony_ci	queue_work(workqueue, work);
122262306a36Sopenharmony_ci	destroy_workqueue(workqueue);
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test,
122562306a36Sopenharmony_ci		((volatile struct work_struct *)work)->data);
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistatic void vmalloc_helpers_tags(struct kunit *test)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	void *ptr;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	/* This test is intended for tag-based modes. */
123362306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_VMALLOC);
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	ptr = vmalloc(PAGE_SIZE);
123862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	/* Check that the returned pointer is tagged. */
124162306a36Sopenharmony_ci	KUNIT_EXPECT_GE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_MIN);
124262306a36Sopenharmony_ci	KUNIT_EXPECT_LT(test, (u8)get_tag(ptr), (u8)KASAN_TAG_KERNEL);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	/* Make sure exported vmalloc helpers handle tagged pointers. */
124562306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, is_vmalloc_addr(ptr));
124662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vmalloc_to_page(ptr));
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci#if !IS_MODULE(CONFIG_KASAN_KUNIT_TEST)
124962306a36Sopenharmony_ci	{
125062306a36Sopenharmony_ci		int rv;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci		/* Make sure vmalloc'ed memory permissions can be changed. */
125362306a36Sopenharmony_ci		rv = set_memory_ro((unsigned long)ptr, 1);
125462306a36Sopenharmony_ci		KUNIT_ASSERT_GE(test, rv, 0);
125562306a36Sopenharmony_ci		rv = set_memory_rw((unsigned long)ptr, 1);
125662306a36Sopenharmony_ci		KUNIT_ASSERT_GE(test, rv, 0);
125762306a36Sopenharmony_ci	}
125862306a36Sopenharmony_ci#endif
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	vfree(ptr);
126162306a36Sopenharmony_ci}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_cistatic void vmalloc_oob(struct kunit *test)
126462306a36Sopenharmony_ci{
126562306a36Sopenharmony_ci	char *v_ptr, *p_ptr;
126662306a36Sopenharmony_ci	struct page *page;
126762306a36Sopenharmony_ci	size_t size = PAGE_SIZE / 2 - KASAN_GRANULE_SIZE - 5;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_VMALLOC);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	v_ptr = vmalloc(size);
127262306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, v_ptr);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	OPTIMIZER_HIDE_VAR(v_ptr);
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	/*
127762306a36Sopenharmony_ci	 * We have to be careful not to hit the guard page in vmalloc tests.
127862306a36Sopenharmony_ci	 * The MMU will catch that and crash us.
127962306a36Sopenharmony_ci	 */
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	/* Make sure in-bounds accesses are valid. */
128262306a36Sopenharmony_ci	v_ptr[0] = 0;
128362306a36Sopenharmony_ci	v_ptr[size - 1] = 0;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	/*
128662306a36Sopenharmony_ci	 * An unaligned access past the requested vmalloc size.
128762306a36Sopenharmony_ci	 * Only generic KASAN can precisely detect these.
128862306a36Sopenharmony_ci	 */
128962306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_KASAN_GENERIC))
129062306a36Sopenharmony_ci		KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)v_ptr)[size]);
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	/* An aligned access into the first out-of-bounds granule. */
129362306a36Sopenharmony_ci	KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)v_ptr)[size + 5]);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	/* Check that in-bounds accesses to the physical page are valid. */
129662306a36Sopenharmony_ci	page = vmalloc_to_page(v_ptr);
129762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, page);
129862306a36Sopenharmony_ci	p_ptr = page_address(page);
129962306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, p_ptr);
130062306a36Sopenharmony_ci	p_ptr[0] = 0;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	vfree(v_ptr);
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	/*
130562306a36Sopenharmony_ci	 * We can't check for use-after-unmap bugs in this nor in the following
130662306a36Sopenharmony_ci	 * vmalloc tests, as the page might be fully unmapped and accessing it
130762306a36Sopenharmony_ci	 * will crash the kernel.
130862306a36Sopenharmony_ci	 */
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_cistatic void vmap_tags(struct kunit *test)
131262306a36Sopenharmony_ci{
131362306a36Sopenharmony_ci	char *p_ptr, *v_ptr;
131462306a36Sopenharmony_ci	struct page *p_page, *v_page;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	/*
131762306a36Sopenharmony_ci	 * This test is specifically crafted for the software tag-based mode,
131862306a36Sopenharmony_ci	 * the only tag-based mode that poisons vmap mappings.
131962306a36Sopenharmony_ci	 */
132062306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_SW_TAGS);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_VMALLOC);
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	p_page = alloc_pages(GFP_KERNEL, 1);
132562306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, p_page);
132662306a36Sopenharmony_ci	p_ptr = page_address(p_page);
132762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, p_ptr);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	v_ptr = vmap(&p_page, 1, VM_MAP, PAGE_KERNEL);
133062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, v_ptr);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	/*
133362306a36Sopenharmony_ci	 * We can't check for out-of-bounds bugs in this nor in the following
133462306a36Sopenharmony_ci	 * vmalloc tests, as allocations have page granularity and accessing
133562306a36Sopenharmony_ci	 * the guard page will crash the kernel.
133662306a36Sopenharmony_ci	 */
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	KUNIT_EXPECT_GE(test, (u8)get_tag(v_ptr), (u8)KASAN_TAG_MIN);
133962306a36Sopenharmony_ci	KUNIT_EXPECT_LT(test, (u8)get_tag(v_ptr), (u8)KASAN_TAG_KERNEL);
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	/* Make sure that in-bounds accesses through both pointers work. */
134262306a36Sopenharmony_ci	*p_ptr = 0;
134362306a36Sopenharmony_ci	*v_ptr = 0;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	/* Make sure vmalloc_to_page() correctly recovers the page pointer. */
134662306a36Sopenharmony_ci	v_page = vmalloc_to_page(v_ptr);
134762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, v_page);
134862306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, p_page, v_page);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	vunmap(v_ptr);
135162306a36Sopenharmony_ci	free_pages((unsigned long)p_ptr, 1);
135262306a36Sopenharmony_ci}
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_cistatic void vm_map_ram_tags(struct kunit *test)
135562306a36Sopenharmony_ci{
135662306a36Sopenharmony_ci	char *p_ptr, *v_ptr;
135762306a36Sopenharmony_ci	struct page *page;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	/*
136062306a36Sopenharmony_ci	 * This test is specifically crafted for the software tag-based mode,
136162306a36Sopenharmony_ci	 * the only tag-based mode that poisons vm_map_ram mappings.
136262306a36Sopenharmony_ci	 */
136362306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_SW_TAGS);
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	page = alloc_pages(GFP_KERNEL, 1);
136662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, page);
136762306a36Sopenharmony_ci	p_ptr = page_address(page);
136862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, p_ptr);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	v_ptr = vm_map_ram(&page, 1, -1);
137162306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, v_ptr);
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	KUNIT_EXPECT_GE(test, (u8)get_tag(v_ptr), (u8)KASAN_TAG_MIN);
137462306a36Sopenharmony_ci	KUNIT_EXPECT_LT(test, (u8)get_tag(v_ptr), (u8)KASAN_TAG_KERNEL);
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	/* Make sure that in-bounds accesses through both pointers work. */
137762306a36Sopenharmony_ci	*p_ptr = 0;
137862306a36Sopenharmony_ci	*v_ptr = 0;
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	vm_unmap_ram(v_ptr, 1);
138162306a36Sopenharmony_ci	free_pages((unsigned long)p_ptr, 1);
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_cistatic void vmalloc_percpu(struct kunit *test)
138562306a36Sopenharmony_ci{
138662306a36Sopenharmony_ci	char __percpu *ptr;
138762306a36Sopenharmony_ci	int cpu;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	/*
139062306a36Sopenharmony_ci	 * This test is specifically crafted for the software tag-based mode,
139162306a36Sopenharmony_ci	 * the only tag-based mode that poisons percpu mappings.
139262306a36Sopenharmony_ci	 */
139362306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_SW_TAGS);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	ptr = __alloc_percpu(PAGE_SIZE, PAGE_SIZE);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	for_each_possible_cpu(cpu) {
139862306a36Sopenharmony_ci		char *c_ptr = per_cpu_ptr(ptr, cpu);
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci		KUNIT_EXPECT_GE(test, (u8)get_tag(c_ptr), (u8)KASAN_TAG_MIN);
140162306a36Sopenharmony_ci		KUNIT_EXPECT_LT(test, (u8)get_tag(c_ptr), (u8)KASAN_TAG_KERNEL);
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci		/* Make sure that in-bounds accesses don't crash the kernel. */
140462306a36Sopenharmony_ci		*c_ptr = 0;
140562306a36Sopenharmony_ci	}
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	free_percpu(ptr);
140862306a36Sopenharmony_ci}
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci/*
141162306a36Sopenharmony_ci * Check that the assigned pointer tag falls within the [KASAN_TAG_MIN,
141262306a36Sopenharmony_ci * KASAN_TAG_KERNEL) range (note: excluding the match-all tag) for tag-based
141362306a36Sopenharmony_ci * modes.
141462306a36Sopenharmony_ci */
141562306a36Sopenharmony_cistatic void match_all_not_assigned(struct kunit *test)
141662306a36Sopenharmony_ci{
141762306a36Sopenharmony_ci	char *ptr;
141862306a36Sopenharmony_ci	struct page *pages;
141962306a36Sopenharmony_ci	int i, size, order;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	for (i = 0; i < 256; i++) {
142462306a36Sopenharmony_ci		size = get_random_u32_inclusive(1, 1024);
142562306a36Sopenharmony_ci		ptr = kmalloc(size, GFP_KERNEL);
142662306a36Sopenharmony_ci		KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
142762306a36Sopenharmony_ci		KUNIT_EXPECT_GE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_MIN);
142862306a36Sopenharmony_ci		KUNIT_EXPECT_LT(test, (u8)get_tag(ptr), (u8)KASAN_TAG_KERNEL);
142962306a36Sopenharmony_ci		kfree(ptr);
143062306a36Sopenharmony_ci	}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	for (i = 0; i < 256; i++) {
143362306a36Sopenharmony_ci		order = get_random_u32_inclusive(1, 4);
143462306a36Sopenharmony_ci		pages = alloc_pages(GFP_KERNEL, order);
143562306a36Sopenharmony_ci		ptr = page_address(pages);
143662306a36Sopenharmony_ci		KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
143762306a36Sopenharmony_ci		KUNIT_EXPECT_GE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_MIN);
143862306a36Sopenharmony_ci		KUNIT_EXPECT_LT(test, (u8)get_tag(ptr), (u8)KASAN_TAG_KERNEL);
143962306a36Sopenharmony_ci		free_pages((unsigned long)ptr, order);
144062306a36Sopenharmony_ci	}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_KASAN_VMALLOC))
144362306a36Sopenharmony_ci		return;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	for (i = 0; i < 256; i++) {
144662306a36Sopenharmony_ci		size = get_random_u32_inclusive(1, 1024);
144762306a36Sopenharmony_ci		ptr = vmalloc(size);
144862306a36Sopenharmony_ci		KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
144962306a36Sopenharmony_ci		KUNIT_EXPECT_GE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_MIN);
145062306a36Sopenharmony_ci		KUNIT_EXPECT_LT(test, (u8)get_tag(ptr), (u8)KASAN_TAG_KERNEL);
145162306a36Sopenharmony_ci		vfree(ptr);
145262306a36Sopenharmony_ci	}
145362306a36Sopenharmony_ci}
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci/* Check that 0xff works as a match-all pointer tag for tag-based modes. */
145662306a36Sopenharmony_cistatic void match_all_ptr_tag(struct kunit *test)
145762306a36Sopenharmony_ci{
145862306a36Sopenharmony_ci	char *ptr;
145962306a36Sopenharmony_ci	u8 tag;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC);
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	ptr = kmalloc(128, GFP_KERNEL);
146462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	/* Backup the assigned tag. */
146762306a36Sopenharmony_ci	tag = get_tag(ptr);
146862306a36Sopenharmony_ci	KUNIT_EXPECT_NE(test, tag, (u8)KASAN_TAG_KERNEL);
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	/* Reset the tag to 0xff.*/
147162306a36Sopenharmony_ci	ptr = set_tag(ptr, KASAN_TAG_KERNEL);
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	/* This access shouldn't trigger a KASAN report. */
147462306a36Sopenharmony_ci	*ptr = 0;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	/* Recover the pointer tag and free. */
147762306a36Sopenharmony_ci	ptr = set_tag(ptr, tag);
147862306a36Sopenharmony_ci	kfree(ptr);
147962306a36Sopenharmony_ci}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci/* Check that there are no match-all memory tags for tag-based modes. */
148262306a36Sopenharmony_cistatic void match_all_mem_tag(struct kunit *test)
148362306a36Sopenharmony_ci{
148462306a36Sopenharmony_ci	char *ptr;
148562306a36Sopenharmony_ci	int tag;
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC);
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	ptr = kmalloc(128, GFP_KERNEL);
149062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
149162306a36Sopenharmony_ci	KUNIT_EXPECT_NE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_KERNEL);
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	/* For each possible tag value not matching the pointer tag. */
149462306a36Sopenharmony_ci	for (tag = KASAN_TAG_MIN; tag <= KASAN_TAG_KERNEL; tag++) {
149562306a36Sopenharmony_ci		if (tag == get_tag(ptr))
149662306a36Sopenharmony_ci			continue;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci		/* Mark the first memory granule with the chosen memory tag. */
149962306a36Sopenharmony_ci		kasan_poison(ptr, KASAN_GRANULE_SIZE, (u8)tag, false);
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci		/* This access must cause a KASAN report. */
150262306a36Sopenharmony_ci		KUNIT_EXPECT_KASAN_FAIL(test, *ptr = 0);
150362306a36Sopenharmony_ci	}
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	/* Recover the memory tag and free. */
150662306a36Sopenharmony_ci	kasan_poison(ptr, KASAN_GRANULE_SIZE, get_tag(ptr), false);
150762306a36Sopenharmony_ci	kfree(ptr);
150862306a36Sopenharmony_ci}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_cistatic struct kunit_case kasan_kunit_test_cases[] = {
151162306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_oob_right),
151262306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_oob_left),
151362306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_node_oob_right),
151462306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_pagealloc_oob_right),
151562306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_pagealloc_uaf),
151662306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_pagealloc_invalid_free),
151762306a36Sopenharmony_ci	KUNIT_CASE(pagealloc_oob_right),
151862306a36Sopenharmony_ci	KUNIT_CASE(pagealloc_uaf),
151962306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_large_oob_right),
152062306a36Sopenharmony_ci	KUNIT_CASE(krealloc_more_oob),
152162306a36Sopenharmony_ci	KUNIT_CASE(krealloc_less_oob),
152262306a36Sopenharmony_ci	KUNIT_CASE(krealloc_pagealloc_more_oob),
152362306a36Sopenharmony_ci	KUNIT_CASE(krealloc_pagealloc_less_oob),
152462306a36Sopenharmony_ci	KUNIT_CASE(krealloc_uaf),
152562306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_oob_16),
152662306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_uaf_16),
152762306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_oob_in_memset),
152862306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_oob_memset_2),
152962306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_oob_memset_4),
153062306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_oob_memset_8),
153162306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_oob_memset_16),
153262306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_memmove_negative_size),
153362306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_memmove_invalid_size),
153462306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_uaf),
153562306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_uaf_memset),
153662306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_uaf2),
153762306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_uaf3),
153862306a36Sopenharmony_ci	KUNIT_CASE(kfree_via_page),
153962306a36Sopenharmony_ci	KUNIT_CASE(kfree_via_phys),
154062306a36Sopenharmony_ci	KUNIT_CASE(kmem_cache_oob),
154162306a36Sopenharmony_ci	KUNIT_CASE(kmem_cache_accounted),
154262306a36Sopenharmony_ci	KUNIT_CASE(kmem_cache_bulk),
154362306a36Sopenharmony_ci	KUNIT_CASE(kasan_global_oob_right),
154462306a36Sopenharmony_ci	KUNIT_CASE(kasan_global_oob_left),
154562306a36Sopenharmony_ci	KUNIT_CASE(kasan_stack_oob),
154662306a36Sopenharmony_ci	KUNIT_CASE(kasan_alloca_oob_left),
154762306a36Sopenharmony_ci	KUNIT_CASE(kasan_alloca_oob_right),
154862306a36Sopenharmony_ci	KUNIT_CASE(ksize_unpoisons_memory),
154962306a36Sopenharmony_ci	KUNIT_CASE(ksize_uaf),
155062306a36Sopenharmony_ci	KUNIT_CASE(kmem_cache_double_free),
155162306a36Sopenharmony_ci	KUNIT_CASE(kmem_cache_invalid_free),
155262306a36Sopenharmony_ci	KUNIT_CASE(kmem_cache_double_destroy),
155362306a36Sopenharmony_ci	KUNIT_CASE(kasan_memchr),
155462306a36Sopenharmony_ci	KUNIT_CASE(kasan_memcmp),
155562306a36Sopenharmony_ci	KUNIT_CASE(kasan_strings),
155662306a36Sopenharmony_ci	KUNIT_CASE(kasan_bitops_generic),
155762306a36Sopenharmony_ci	KUNIT_CASE(kasan_bitops_tags),
155862306a36Sopenharmony_ci	KUNIT_CASE(kmalloc_double_kzfree),
155962306a36Sopenharmony_ci	KUNIT_CASE(rcu_uaf),
156062306a36Sopenharmony_ci	KUNIT_CASE(workqueue_uaf),
156162306a36Sopenharmony_ci	KUNIT_CASE(vmalloc_helpers_tags),
156262306a36Sopenharmony_ci	KUNIT_CASE(vmalloc_oob),
156362306a36Sopenharmony_ci	KUNIT_CASE(vmap_tags),
156462306a36Sopenharmony_ci	KUNIT_CASE(vm_map_ram_tags),
156562306a36Sopenharmony_ci	KUNIT_CASE(vmalloc_percpu),
156662306a36Sopenharmony_ci	KUNIT_CASE(match_all_not_assigned),
156762306a36Sopenharmony_ci	KUNIT_CASE(match_all_ptr_tag),
156862306a36Sopenharmony_ci	KUNIT_CASE(match_all_mem_tag),
156962306a36Sopenharmony_ci	{}
157062306a36Sopenharmony_ci};
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_cistatic struct kunit_suite kasan_kunit_test_suite = {
157362306a36Sopenharmony_ci	.name = "kasan",
157462306a36Sopenharmony_ci	.test_cases = kasan_kunit_test_cases,
157562306a36Sopenharmony_ci	.exit = kasan_test_exit,
157662306a36Sopenharmony_ci	.suite_init = kasan_suite_init,
157762306a36Sopenharmony_ci	.suite_exit = kasan_suite_exit,
157862306a36Sopenharmony_ci};
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_cikunit_test_suite(kasan_kunit_test_suite);
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1583