File Index
Files and directories
Sign in
FILE

randstruct_kunit.c

File preview with syntax highlighting.

linux-6.19.14/lib/tests/randstruct_kunit.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Test cases for struct randomization, i.e. CONFIG_RANDSTRUCT=y.
  4 *
  5 * For example, see:
  6 * "Running tests with kunit_tool" at Documentation/dev-tools/kunit/start.rst
  7 *	./tools/testing/kunit/kunit.py run randstruct [--raw_output] \
  8 *		[--make_option LLVM=1] \
  9 *		--kconfig_add CONFIG_RANDSTRUCT_FULL=y
 10 *
 11 */
 12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 13
 14#include <kunit/test.h>
 15#include <linux/init.h>
 16#include <linux/kernel.h>
 17#include <linux/module.h>
 18#include <linux/string.h>
 19
 20#define DO_MANY_MEMBERS(macro, args...)	\
 21	macro(a, args)			\
 22	macro(b, args)			\
 23	macro(c, args)			\
 24	macro(d, args)			\
 25	macro(e, args)			\
 26	macro(f, args)			\
 27	macro(g, args)			\
 28	macro(h, args)
 29
 30#define do_enum(x, ignored)	MEMBER_NAME_ ## x,
 31enum randstruct_member_names {
 32	DO_MANY_MEMBERS(do_enum)
 33	MEMBER_NAME_MAX,
 34};
 35/* Make sure the macros are working: want 8 test members. */
 36_Static_assert(MEMBER_NAME_MAX == 8, "Number of test members changed?!");
 37
 38/* This is an unsigned long member to match the function pointer size */
 39#define unsigned_long_member(x, ignored)	unsigned long x;
 40struct randstruct_untouched {
 41	DO_MANY_MEMBERS(unsigned_long_member)
 42};
 43
 44/* Struct explicitly marked with __randomize_layout. */
 45struct randstruct_shuffled {
 46	DO_MANY_MEMBERS(unsigned_long_member)
 47} __randomize_layout;
 48#undef unsigned_long_member
 49
 50/* Struct implicitly randomized from being all func ptrs. */
 51#define func_member(x, ignored)	size_t (*x)(int);
 52struct randstruct_funcs_untouched {
 53	DO_MANY_MEMBERS(func_member)
 54} __no_randomize_layout;
 55
 56struct randstruct_funcs_shuffled {
 57	DO_MANY_MEMBERS(func_member)
 58};
 59
 60#define func_body(x, ignored)					\
 61static noinline size_t func_##x(int arg)			\
 62{								\
 63	return offsetof(struct randstruct_funcs_untouched, x);	\
 64}
 65DO_MANY_MEMBERS(func_body)
 66
 67/* Various mixed types. */
 68#define mixed_members					\
 69	bool a;						\
 70	short b;					\
 71	unsigned int c __aligned(16);			\
 72	size_t d;					\
 73	char e;						\
 74	u64 f;						\
 75	union {						\
 76		struct randstruct_shuffled shuffled;	\
 77		uintptr_t g;				\
 78	};						\
 79	union {						\
 80		void *ptr;				\
 81		char h;					\
 82	};
 83
 84struct randstruct_mixed_untouched {
 85	mixed_members
 86};
 87
 88struct randstruct_mixed_shuffled {
 89	mixed_members
 90} __randomize_layout;
 91#undef mixed_members
 92
 93struct contains_randstruct_untouched {
 94	int before;
 95	struct randstruct_untouched untouched;
 96	int after;
 97};
 98
 99struct contains_randstruct_shuffled {
100	int before;
101	struct randstruct_shuffled shuffled;
102	int after;
103};
104
105struct contains_func_untouched {
106	struct randstruct_funcs_shuffled inner;
107	DO_MANY_MEMBERS(func_member)
108} __no_randomize_layout;
109
110struct contains_func_shuffled {
111	struct randstruct_funcs_shuffled inner;
112	DO_MANY_MEMBERS(func_member)
113};
114#undef func_member
115
116#define check_mismatch(x, untouched, shuffled)	\
117	if (offsetof(untouched, x) != offsetof(shuffled, x))	\
118		mismatches++;					\
119	kunit_info(test, #shuffled "::" #x " @ %zu (vs %zu)\n",	\
120		   offsetof(shuffled, x),			\
121		   offsetof(untouched, x));			\
122
123#define check_pair(outcome, untouched, shuffled, checker...)	\
124	mismatches = 0;						\
125	DO_MANY_MEMBERS(checker, untouched, shuffled)	\
126	kunit_info(test, "Differing " #untouched " vs " #shuffled " member positions: %d\n", \
127		   mismatches);					\
128	KUNIT_##outcome##_MSG(test, mismatches, 0,		\
129			      #untouched " vs " #shuffled " layouts: unlucky or broken?\n");
130
131static void randstruct_layout_same(struct kunit *test)
132{
133	int mismatches;
134
135	check_pair(EXPECT_EQ, struct randstruct_untouched, struct randstruct_untouched,
136		   check_mismatch)
137	check_pair(EXPECT_GT, struct randstruct_untouched, struct randstruct_shuffled,
138		   check_mismatch)
139}
140
141static void randstruct_layout_mixed(struct kunit *test)
142{
143	int mismatches;
144
145	check_pair(EXPECT_EQ, struct randstruct_mixed_untouched, struct randstruct_mixed_untouched,
146		   check_mismatch)
147	check_pair(EXPECT_GT, struct randstruct_mixed_untouched, struct randstruct_mixed_shuffled,
148		   check_mismatch)
149}
150
151static void randstruct_layout_fptr(struct kunit *test)
152{
153	int mismatches;
154
155	check_pair(EXPECT_EQ, struct randstruct_untouched, struct randstruct_untouched,
156		   check_mismatch)
157	check_pair(EXPECT_GT, struct randstruct_untouched, struct randstruct_funcs_shuffled,
158		   check_mismatch)
159	check_pair(EXPECT_GT, struct randstruct_funcs_untouched, struct randstruct_funcs_shuffled,
160		   check_mismatch)
161}
162
163#define check_mismatch_prefixed(x, prefix, untouched, shuffled)	\
164	check_mismatch(prefix.x, untouched, shuffled)
165
166static void randstruct_layout_fptr_deep(struct kunit *test)
167{
168	int mismatches;
169
170	if (IS_ENABLED(CONFIG_CC_IS_CLANG))
171		kunit_skip(test, "Clang randstruct misses inner functions: https://github.com/llvm/llvm-project/issues/138355");
172
173	check_pair(EXPECT_EQ, struct contains_func_untouched, struct contains_func_untouched,
174			check_mismatch_prefixed, inner)
175
176	check_pair(EXPECT_GT, struct contains_func_untouched, struct contains_func_shuffled,
177			check_mismatch_prefixed, inner)
178}
179
180#undef check_pair
181#undef check_mismatch
182
183#define check_mismatch(x, ignore)				\
184	KUNIT_EXPECT_EQ_MSG(test, untouched->x, shuffled->x,	\
185			    "Mismatched member value in %s initializer\n", \
186			    name);
187
188static void test_check_init(struct kunit *test, const char *name,
189			    struct randstruct_untouched *untouched,
190			    struct randstruct_shuffled *shuffled)
191{
192	DO_MANY_MEMBERS(check_mismatch)
193}
194
195static void test_check_mixed_init(struct kunit *test, const char *name,
196				  struct randstruct_mixed_untouched *untouched,
197				  struct randstruct_mixed_shuffled *shuffled)
198{
199	DO_MANY_MEMBERS(check_mismatch)
200}
201#undef check_mismatch
202
203#define check_mismatch(x, ignore)				\
204	KUNIT_EXPECT_EQ_MSG(test, untouched->untouched.x,	\
205			    shuffled->shuffled.x,		\
206			    "Mismatched member value in %s initializer\n", \
207			    name);
208static void test_check_contained_init(struct kunit *test, const char *name,
209				      struct contains_randstruct_untouched *untouched,
210				      struct contains_randstruct_shuffled *shuffled)
211{
212	DO_MANY_MEMBERS(check_mismatch)
213}
214#undef check_mismatch
215
216#define check_mismatch(x, ignore)					\
217	KUNIT_EXPECT_PTR_EQ_MSG(test, untouched->x, shuffled->x,	\
218			    "Mismatched member value in %s initializer\n", \
219			    name);
220
221static void test_check_funcs_init(struct kunit *test, const char *name,
222				  struct randstruct_funcs_untouched *untouched,
223				  struct randstruct_funcs_shuffled *shuffled)
224{
225	DO_MANY_MEMBERS(check_mismatch)
226}
227#undef check_mismatch
228
229static void randstruct_initializers(struct kunit *test)
230{
231#define init_members		\
232		.a = 1,		\
233		.b = 3,		\
234		.c = 5,		\
235		.d = 7,		\
236		.e = 11,	\
237		.f = 13,	\
238		.g = 17,	\
239		.h = 19,
240	struct randstruct_untouched untouched = {
241		init_members
242	};
243	struct randstruct_shuffled shuffled = {
244		init_members
245	};
246	struct randstruct_mixed_untouched mixed_untouched = {
247		init_members
248	};
249	struct randstruct_mixed_shuffled mixed_shuffled = {
250		init_members
251	};
252	struct contains_randstruct_untouched contains_untouched = {
253		.untouched = {
254			init_members
255		},
256	};
257	struct contains_randstruct_shuffled contains_shuffled = {
258		.shuffled = {
259			init_members
260		},
261	};
262#define func_member(x, ignored)	\
263		.x = func_##x,
264	struct randstruct_funcs_untouched funcs_untouched = {
265		DO_MANY_MEMBERS(func_member)
266	};
267	struct randstruct_funcs_shuffled funcs_shuffled = {
268		DO_MANY_MEMBERS(func_member)
269	};
270
271	test_check_init(test, "named", &untouched, &shuffled);
272	test_check_init(test, "unnamed", &untouched,
273		&(struct randstruct_shuffled){
274			init_members
275		});
276
277	test_check_contained_init(test, "named", &contains_untouched, &contains_shuffled);
278	test_check_contained_init(test, "unnamed", &contains_untouched,
279		&(struct contains_randstruct_shuffled){
280			.shuffled = (struct randstruct_shuffled){
281				init_members
282			},
283		});
284
285	test_check_contained_init(test, "named", &contains_untouched, &contains_shuffled);
286	test_check_contained_init(test, "unnamed copy", &contains_untouched,
287		&(struct contains_randstruct_shuffled){
288			/* full struct copy initializer */
289			.shuffled = shuffled,
290		});
291
292	test_check_mixed_init(test, "named", &mixed_untouched, &mixed_shuffled);
293	test_check_mixed_init(test, "unnamed", &mixed_untouched,
294		&(struct randstruct_mixed_shuffled){
295			init_members
296		});
297
298	test_check_funcs_init(test, "named", &funcs_untouched, &funcs_shuffled);
299	test_check_funcs_init(test, "unnamed", &funcs_untouched,
300		&(struct randstruct_funcs_shuffled){
301			DO_MANY_MEMBERS(func_member)
302		});
303
304#undef func_member
305#undef init_members
306}
307
308static int randstruct_test_init(struct kunit *test)
309{
310	if (!IS_ENABLED(CONFIG_RANDSTRUCT))
311		kunit_skip(test, "Not built with CONFIG_RANDSTRUCT=y");
312
313	return 0;
314}
315
316static struct kunit_case randstruct_test_cases[] = {
317	KUNIT_CASE(randstruct_layout_same),
318	KUNIT_CASE(randstruct_layout_mixed),
319	KUNIT_CASE(randstruct_layout_fptr),
320	KUNIT_CASE(randstruct_layout_fptr_deep),
321	KUNIT_CASE(randstruct_initializers),
322	{}
323};
324
325static struct kunit_suite randstruct_test_suite = {
326	.name = "randstruct",
327	.init = randstruct_test_init,
328	.test_cases = randstruct_test_cases,
329};
330
331kunit_test_suites(&randstruct_test_suite);
332
333MODULE_DESCRIPTION("Test cases for struct randomization");
334MODULE_LICENSE("GPL");
~/ Read-only file preview.