Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.17.
  1// SPDX-License-Identifier: GPL-2.0
  2
  3#include <linux/init.h>
  4#include <linux/kernel.h>
  5#include <linux/printk.h>
  6#include <linux/random.h>
  7#include <linux/types.h>
  8
  9#include "encoding.h"
 10
 11#define ITERS_PER_TEST 2000
 12
 13/* Test requirements. */
 14static bool test_requires(void)
 15{
 16	/* random should be initialized for the below tests */
 17	return prandom_u32() + prandom_u32() != 0;
 18}
 19
 20/*
 21 * Test watchpoint encode and decode: check that encoding some access's info,
 22 * and then subsequent decode preserves the access's info.
 23 */
 24static bool test_encode_decode(void)
 25{
 26	int i;
 27
 28	for (i = 0; i < ITERS_PER_TEST; ++i) {
 29		size_t size = prandom_u32_max(MAX_ENCODABLE_SIZE) + 1;
 30		bool is_write = !!prandom_u32_max(2);
 31		unsigned long addr;
 32
 33		prandom_bytes(&addr, sizeof(addr));
 34		if (WARN_ON(!check_encodable(addr, size)))
 35			return false;
 36
 37		/* Encode and decode */
 38		{
 39			const long encoded_watchpoint =
 40				encode_watchpoint(addr, size, is_write);
 41			unsigned long verif_masked_addr;
 42			size_t verif_size;
 43			bool verif_is_write;
 44
 45			/* Check special watchpoints */
 46			if (WARN_ON(decode_watchpoint(
 47				    INVALID_WATCHPOINT, &verif_masked_addr,
 48				    &verif_size, &verif_is_write)))
 49				return false;
 50			if (WARN_ON(decode_watchpoint(
 51				    CONSUMED_WATCHPOINT, &verif_masked_addr,
 52				    &verif_size, &verif_is_write)))
 53				return false;
 54
 55			/* Check decoding watchpoint returns same data */
 56			if (WARN_ON(!decode_watchpoint(
 57				    encoded_watchpoint, &verif_masked_addr,
 58				    &verif_size, &verif_is_write)))
 59				return false;
 60			if (WARN_ON(verif_masked_addr !=
 61				    (addr & WATCHPOINT_ADDR_MASK)))
 62				goto fail;
 63			if (WARN_ON(verif_size != size))
 64				goto fail;
 65			if (WARN_ON(is_write != verif_is_write))
 66				goto fail;
 67
 68			continue;
 69fail:
 70			pr_err("%s fail: %s %zu bytes @ %lx -> encoded: %lx -> %s %zu bytes @ %lx\n",
 71			       __func__, is_write ? "write" : "read", size,
 72			       addr, encoded_watchpoint,
 73			       verif_is_write ? "write" : "read", verif_size,
 74			       verif_masked_addr);
 75			return false;
 76		}
 77	}
 78
 79	return true;
 80}
 81
 82/* Test access matching function. */
 83static bool test_matching_access(void)
 84{
 85	if (WARN_ON(!matching_access(10, 1, 10, 1)))
 86		return false;
 87	if (WARN_ON(!matching_access(10, 2, 11, 1)))
 88		return false;
 89	if (WARN_ON(!matching_access(10, 1, 9, 2)))
 90		return false;
 91	if (WARN_ON(matching_access(10, 1, 11, 1)))
 92		return false;
 93	if (WARN_ON(matching_access(9, 1, 10, 1)))
 94		return false;
 95
 96	/*
 97	 * An access of size 0 could match another access, as demonstrated here.
 98	 * Rather than add more comparisons to 'matching_access()', which would
 99	 * end up in the fast-path for *all* checks, check_access() simply
100	 * returns for all accesses of size 0.
101	 */
102	if (WARN_ON(!matching_access(8, 8, 12, 0)))
103		return false;
104
105	return true;
106}
107
108static int __init kcsan_selftest(void)
109{
110	int passed = 0;
111	int total = 0;
112
113#define RUN_TEST(do_test)                                                      \
114	do {                                                                   \
115		++total;                                                       \
116		if (do_test())                                                 \
117			++passed;                                              \
118		else                                                           \
119			pr_err("KCSAN selftest: " #do_test " failed");         \
120	} while (0)
121
122	RUN_TEST(test_requires);
123	RUN_TEST(test_encode_decode);
124	RUN_TEST(test_matching_access);
125
126	pr_info("KCSAN selftest: %d/%d tests passed\n", passed, total);
127	if (passed != total)
128		panic("KCSAN selftests failed");
129	return 0;
130}
131postcore_initcall(kcsan_selftest);