Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

lib/tests: Add randstruct KUnit test

Perform basic validation about layout randomization and initialization
tracking when using CONFIG_RANDSTRUCT=y. Tested using:

$ ./tools/testing/kunit/kunit.py run \
--kconfig_add CONFIG_RANDSTRUCT_FULL=y \
randstruct
[17:22:30] ================= randstruct (2 subtests) ==================
[17:22:30] [PASSED] randstruct_layout
[17:22:30] [PASSED] randstruct_initializers
[17:22:30] =================== [PASSED] randstruct ====================
[17:22:30] ============================================================
[17:22:30] Testing complete. Ran 2 tests: passed: 2
[17:22:30] Elapsed time: 5.091s total, 0.001s configuring, 4.974s building, 0.086s running

Adding "--make_option LLVM=1" can be used to test Clang, which also
passes.

Acked-by: David Gow <davidgow@google.com>
Signed-off-by: Kees Cook <kees@kernel.org>

+293
+1
MAINTAINERS
··· 12892 12892 F: include/linux/randomize_kstack.h 12893 12893 F: include/linux/ucopysize.h 12894 12894 F: kernel/configs/hardening.config 12895 + F: lib/tests/randstruct_kunit.c 12895 12896 F: lib/tests/usercopy_kunit.c 12896 12897 F: mm/usercopy.c 12897 12898 F: security/Kconfig.hardening
+8
lib/Kconfig.debug
··· 2863 2863 2864 2864 If unsure, say N. 2865 2865 2866 + config RANDSTRUCT_KUNIT_TEST 2867 + tristate "Test randstruct structure layout randomization at runtime" if !KUNIT_ALL_TESTS 2868 + depends on KUNIT 2869 + default KUNIT_ALL_TESTS 2870 + help 2871 + Builds unit tests for the checking CONFIG_RANDSTRUCT=y, which 2872 + randomizes structure layouts. 2873 + 2866 2874 config STACKINIT_KUNIT_TEST 2867 2875 tristate "Test level of stack variable initialization" if !KUNIT_ALL_TESTS 2868 2876 depends on KUNIT
+1
lib/tests/Makefile
··· 35 35 CFLAGS_overflow_kunit.o = $(call cc-disable-warning, tautological-constant-out-of-range-compare) 36 36 obj-$(CONFIG_OVERFLOW_KUNIT_TEST) += overflow_kunit.o 37 37 obj-$(CONFIG_PRINTF_KUNIT_TEST) += printf_kunit.o 38 + obj-$(CONFIG_RANDSTRUCT_KUNIT_TEST) += randstruct_kunit.o 38 39 obj-$(CONFIG_SCANF_KUNIT_TEST) += scanf_kunit.o 39 40 obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o 40 41 obj-$(CONFIG_SLUB_KUNIT_TEST) += slub_kunit.o
+283
lib/tests/randstruct_kunit.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, 31 + enum 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; 40 + struct randstruct_untouched { 41 + DO_MANY_MEMBERS(unsigned_long_member) 42 + }; 43 + 44 + /* Struct explicitly marked with __randomize_layout. */ 45 + struct 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); 52 + struct randstruct_funcs_untouched { 53 + DO_MANY_MEMBERS(func_member) 54 + } __no_randomize_layout; 55 + 56 + struct randstruct_funcs_shuffled { 57 + DO_MANY_MEMBERS(func_member) 58 + }; 59 + #undef func_member 60 + 61 + #define func_body(x, ignored) \ 62 + static noinline size_t func_##x(int arg) \ 63 + { \ 64 + return offsetof(struct randstruct_funcs_untouched, x); \ 65 + } 66 + DO_MANY_MEMBERS(func_body) 67 + 68 + /* Various mixed types. */ 69 + #define mixed_members \ 70 + bool a; \ 71 + short b; \ 72 + unsigned int c __aligned(16); \ 73 + size_t d; \ 74 + char e; \ 75 + u64 f; \ 76 + union { \ 77 + struct randstruct_shuffled shuffled; \ 78 + uintptr_t g; \ 79 + }; \ 80 + union { \ 81 + void *ptr; \ 82 + char h; \ 83 + }; 84 + 85 + struct randstruct_mixed_untouched { 86 + mixed_members 87 + }; 88 + 89 + struct randstruct_mixed_shuffled { 90 + mixed_members 91 + } __randomize_layout; 92 + #undef mixed_members 93 + 94 + struct contains_randstruct_untouched { 95 + int before; 96 + struct randstruct_untouched untouched; 97 + int after; 98 + }; 99 + 100 + struct contains_randstruct_shuffled { 101 + int before; 102 + struct randstruct_shuffled shuffled; 103 + int after; 104 + }; 105 + 106 + static void randstruct_layout(struct kunit *test) 107 + { 108 + int mismatches; 109 + 110 + #define check_mismatch(x, untouched, shuffled) \ 111 + if (offsetof(untouched, x) != offsetof(shuffled, x)) \ 112 + mismatches++; \ 113 + kunit_info(test, #shuffled "::" #x " @ %zu (vs %zu)\n", \ 114 + offsetof(shuffled, x), \ 115 + offsetof(untouched, x)); \ 116 + 117 + #define check_pair(outcome, untouched, shuffled) \ 118 + mismatches = 0; \ 119 + DO_MANY_MEMBERS(check_mismatch, untouched, shuffled) \ 120 + kunit_info(test, "Differing " #untouched " vs " #shuffled " member positions: %d\n", \ 121 + mismatches); \ 122 + KUNIT_##outcome##_MSG(test, mismatches, 0, \ 123 + #untouched " vs " #shuffled " layouts: unlucky or broken?\n"); 124 + 125 + check_pair(EXPECT_EQ, struct randstruct_untouched, struct randstruct_untouched) 126 + check_pair(EXPECT_GT, struct randstruct_untouched, struct randstruct_shuffled) 127 + check_pair(EXPECT_GT, struct randstruct_untouched, struct randstruct_funcs_shuffled) 128 + check_pair(EXPECT_GT, struct randstruct_funcs_untouched, struct randstruct_funcs_shuffled) 129 + check_pair(EXPECT_GT, struct randstruct_mixed_untouched, struct randstruct_mixed_shuffled) 130 + #undef check_pair 131 + 132 + #undef check_mismatch 133 + } 134 + 135 + #define check_mismatch(x, ignore) \ 136 + KUNIT_EXPECT_EQ_MSG(test, untouched->x, shuffled->x, \ 137 + "Mismatched member value in %s initializer\n", \ 138 + name); 139 + 140 + static void test_check_init(struct kunit *test, const char *name, 141 + struct randstruct_untouched *untouched, 142 + struct randstruct_shuffled *shuffled) 143 + { 144 + DO_MANY_MEMBERS(check_mismatch) 145 + } 146 + 147 + static void test_check_mixed_init(struct kunit *test, const char *name, 148 + struct randstruct_mixed_untouched *untouched, 149 + struct randstruct_mixed_shuffled *shuffled) 150 + { 151 + DO_MANY_MEMBERS(check_mismatch) 152 + } 153 + #undef check_mismatch 154 + 155 + #define check_mismatch(x, ignore) \ 156 + KUNIT_EXPECT_EQ_MSG(test, untouched->untouched.x, \ 157 + shuffled->shuffled.x, \ 158 + "Mismatched member value in %s initializer\n", \ 159 + name); 160 + static void test_check_contained_init(struct kunit *test, const char *name, 161 + struct contains_randstruct_untouched *untouched, 162 + struct contains_randstruct_shuffled *shuffled) 163 + { 164 + DO_MANY_MEMBERS(check_mismatch) 165 + } 166 + #undef check_mismatch 167 + 168 + #define check_mismatch(x, ignore) \ 169 + KUNIT_EXPECT_PTR_EQ_MSG(test, untouched->x, shuffled->x, \ 170 + "Mismatched member value in %s initializer\n", \ 171 + name); 172 + 173 + static void test_check_funcs_init(struct kunit *test, const char *name, 174 + struct randstruct_funcs_untouched *untouched, 175 + struct randstruct_funcs_shuffled *shuffled) 176 + { 177 + DO_MANY_MEMBERS(check_mismatch) 178 + } 179 + #undef check_mismatch 180 + 181 + static void randstruct_initializers(struct kunit *test) 182 + { 183 + #define init_members \ 184 + .a = 1, \ 185 + .b = 3, \ 186 + .c = 5, \ 187 + .d = 7, \ 188 + .e = 11, \ 189 + .f = 13, \ 190 + .g = 17, \ 191 + .h = 19, 192 + struct randstruct_untouched untouched = { 193 + init_members 194 + }; 195 + struct randstruct_shuffled shuffled = { 196 + init_members 197 + }; 198 + struct randstruct_mixed_untouched mixed_untouched = { 199 + init_members 200 + }; 201 + struct randstruct_mixed_shuffled mixed_shuffled = { 202 + init_members 203 + }; 204 + struct contains_randstruct_untouched contains_untouched = { 205 + .untouched = { 206 + init_members 207 + }, 208 + }; 209 + struct contains_randstruct_shuffled contains_shuffled = { 210 + .shuffled = { 211 + init_members 212 + }, 213 + }; 214 + #define func_member(x, ignored) \ 215 + .x = func_##x, 216 + struct randstruct_funcs_untouched funcs_untouched = { 217 + DO_MANY_MEMBERS(func_member) 218 + }; 219 + struct randstruct_funcs_shuffled funcs_shuffled = { 220 + DO_MANY_MEMBERS(func_member) 221 + }; 222 + 223 + test_check_init(test, "named", &untouched, &shuffled); 224 + test_check_init(test, "unnamed", &untouched, 225 + &(struct randstruct_shuffled){ 226 + init_members 227 + }); 228 + 229 + test_check_contained_init(test, "named", &contains_untouched, &contains_shuffled); 230 + test_check_contained_init(test, "unnamed", &contains_untouched, 231 + &(struct contains_randstruct_shuffled){ 232 + .shuffled = (struct randstruct_shuffled){ 233 + init_members 234 + }, 235 + }); 236 + 237 + test_check_contained_init(test, "named", &contains_untouched, &contains_shuffled); 238 + test_check_contained_init(test, "unnamed copy", &contains_untouched, 239 + &(struct contains_randstruct_shuffled){ 240 + /* full struct copy initializer */ 241 + .shuffled = shuffled, 242 + }); 243 + 244 + test_check_mixed_init(test, "named", &mixed_untouched, &mixed_shuffled); 245 + test_check_mixed_init(test, "unnamed", &mixed_untouched, 246 + &(struct randstruct_mixed_shuffled){ 247 + init_members 248 + }); 249 + 250 + test_check_funcs_init(test, "named", &funcs_untouched, &funcs_shuffled); 251 + test_check_funcs_init(test, "unnamed", &funcs_untouched, 252 + &(struct randstruct_funcs_shuffled){ 253 + DO_MANY_MEMBERS(func_member) 254 + }); 255 + 256 + #undef func_member 257 + #undef init_members 258 + } 259 + 260 + static int randstruct_test_init(struct kunit *test) 261 + { 262 + if (!IS_ENABLED(CONFIG_RANDSTRUCT)) 263 + kunit_skip(test, "Not built with CONFIG_RANDSTRUCT=y"); 264 + 265 + return 0; 266 + } 267 + 268 + static struct kunit_case randstruct_test_cases[] = { 269 + KUNIT_CASE(randstruct_layout), 270 + KUNIT_CASE(randstruct_initializers), 271 + {} 272 + }; 273 + 274 + static struct kunit_suite randstruct_test_suite = { 275 + .name = "randstruct", 276 + .init = randstruct_test_init, 277 + .test_cases = randstruct_test_cases, 278 + }; 279 + 280 + kunit_test_suites(&randstruct_test_suite); 281 + 282 + MODULE_DESCRIPTION("Test cases for struct randomization"); 283 + MODULE_LICENSE("GPL");