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