Linux Audio

Check our new training course

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