Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335// SPDX-License-Identifier: GPL-2.0-or-later/* * Test cases for struct randomization, i.e. CONFIG_RANDSTRUCT=y. * * For example, see: * "Running tests with kunit_tool" at Documentation/dev-tools/kunit/start.rst * ./tools/testing/kunit/kunit.py run randstruct [--raw_output] \ * [--make_option LLVM=1] \ * --kconfig_add CONFIG_RANDSTRUCT_FULL=y * */#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <kunit/test.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/string.h>
#define DO_MANY_MEMBERS(macro, args...) \ macro(a, args) \ macro(b, args) \ macro(c, args) \ macro(d, args) \ macro(e, args) \ macro(f, args) \ macro(g, args) \ macro(h, args)
#define do_enum(x, ignored) MEMBER_NAME_ ## x,enum randstruct_member_names { DO_MANY_MEMBERS(do_enum) MEMBER_NAME_MAX,};/* Make sure the macros are working: want 8 test members. */_Static_assert(MEMBER_NAME_MAX == 8, "Number of test members changed?!");
/* This is an unsigned long member to match the function pointer size */#define unsigned_long_member(x, ignored) unsigned long x;struct randstruct_untouched { DO_MANY_MEMBERS(unsigned_long_member)};
/* Struct explicitly marked with __randomize_layout. */struct randstruct_shuffled { DO_MANY_MEMBERS(unsigned_long_member)} __randomize_layout;#undef unsigned_long_member
/* Struct implicitly randomized from being all func ptrs. */#define func_member(x, ignored) size_t (*x)(int);struct randstruct_funcs_untouched { DO_MANY_MEMBERS(func_member)} __no_randomize_layout;
struct randstruct_funcs_shuffled { DO_MANY_MEMBERS(func_member)};
#define func_body(x, ignored) \static noinline size_t func_##x(int arg) \{ \ return offsetof(struct randstruct_funcs_untouched, x); \}DO_MANY_MEMBERS(func_body)
/* Various mixed types. */#define mixed_members \ bool a; \ short b; \ unsigned int c __aligned(16); \ size_t d; \ char e; \ u64 f; \ union { \ struct randstruct_shuffled shuffled; \ uintptr_t g; \ }; \ union { \ void *ptr; \ char h; \ };
struct randstruct_mixed_untouched { mixed_members};
struct randstruct_mixed_shuffled { mixed_members} __randomize_layout;#undef mixed_members
struct contains_randstruct_untouched { int before; struct randstruct_untouched untouched; int after;};
struct contains_randstruct_shuffled { int before; struct randstruct_shuffled shuffled; int after;};
struct contains_func_untouched { struct randstruct_funcs_shuffled inner; DO_MANY_MEMBERS(func_member)} __no_randomize_layout;
struct contains_func_shuffled { struct randstruct_funcs_shuffled inner; DO_MANY_MEMBERS(func_member)};#undef func_member
#define check_mismatch(x, untouched, shuffled) \ if (offsetof(untouched, x) != offsetof(shuffled, x)) \ mismatches++; \ kunit_info(test, #shuffled "::" #x " @ %zu (vs %zu)\n", \ offsetof(shuffled, x), \ offsetof(untouched, x)); \
#define check_pair(outcome, untouched, shuffled, checker...) \ mismatches = 0; \ DO_MANY_MEMBERS(checker, untouched, shuffled) \ kunit_info(test, "Differing " #untouched " vs " #shuffled " member positions: %d\n", \ mismatches); \ KUNIT_##outcome##_MSG(test, mismatches, 0, \ #untouched " vs " #shuffled " layouts: unlucky or broken?\n");
static void randstruct_layout_same(struct kunit *test){ int mismatches;
check_pair(EXPECT_EQ, struct randstruct_untouched, struct randstruct_untouched, check_mismatch) check_pair(EXPECT_GT, struct randstruct_untouched, struct randstruct_shuffled, check_mismatch)}
static void randstruct_layout_mixed(struct kunit *test){ int mismatches;
check_pair(EXPECT_EQ, struct randstruct_mixed_untouched, struct randstruct_mixed_untouched, check_mismatch) check_pair(EXPECT_GT, struct randstruct_mixed_untouched, struct randstruct_mixed_shuffled, check_mismatch)}
static void randstruct_layout_fptr(struct kunit *test){ int mismatches;
check_pair(EXPECT_EQ, struct randstruct_untouched, struct randstruct_untouched, check_mismatch) check_pair(EXPECT_GT, struct randstruct_untouched, struct randstruct_funcs_shuffled, check_mismatch) check_pair(EXPECT_GT, struct randstruct_funcs_untouched, struct randstruct_funcs_shuffled, check_mismatch)}
#define check_mismatch_prefixed(x, prefix, untouched, shuffled) \ check_mismatch(prefix.x, untouched, shuffled)
static void randstruct_layout_fptr_deep(struct kunit *test){ int mismatches;
if (IS_ENABLED(CONFIG_CC_IS_CLANG)) kunit_skip(test, "Clang randstruct misses inner functions: https://github.com/llvm/llvm-project/issues/138355");
check_pair(EXPECT_EQ, struct contains_func_untouched, struct contains_func_untouched, check_mismatch_prefixed, inner)
check_pair(EXPECT_GT, struct contains_func_untouched, struct contains_func_shuffled, check_mismatch_prefixed, inner)}
#undef check_pair#undef check_mismatch
#define check_mismatch(x, ignore) \ KUNIT_EXPECT_EQ_MSG(test, untouched->x, shuffled->x, \ "Mismatched member value in %s initializer\n", \ name);
static void test_check_init(struct kunit *test, const char *name, struct randstruct_untouched *untouched, struct randstruct_shuffled *shuffled){ DO_MANY_MEMBERS(check_mismatch)}
static void test_check_mixed_init(struct kunit *test, const char *name, struct randstruct_mixed_untouched *untouched, struct randstruct_mixed_shuffled *shuffled){ DO_MANY_MEMBERS(check_mismatch)}#undef check_mismatch
#define check_mismatch(x, ignore) \ KUNIT_EXPECT_EQ_MSG(test, untouched->untouched.x, \ shuffled->shuffled.x, \ "Mismatched member value in %s initializer\n", \ name);static void test_check_contained_init(struct kunit *test, const char *name, struct contains_randstruct_untouched *untouched, struct contains_randstruct_shuffled *shuffled){ DO_MANY_MEMBERS(check_mismatch)}#undef check_mismatch
#define check_mismatch(x, ignore) \ KUNIT_EXPECT_PTR_EQ_MSG(test, untouched->x, shuffled->x, \ "Mismatched member value in %s initializer\n", \ name);
static void test_check_funcs_init(struct kunit *test, const char *name, struct randstruct_funcs_untouched *untouched, struct randstruct_funcs_shuffled *shuffled){ DO_MANY_MEMBERS(check_mismatch)}#undef check_mismatch
static void randstruct_initializers(struct kunit *test){#define init_members \ .a = 1, \ .b = 3, \ .c = 5, \ .d = 7, \ .e = 11, \ .f = 13, \ .g = 17, \ .h = 19, struct randstruct_untouched untouched = { init_members }; struct randstruct_shuffled shuffled = { init_members }; struct randstruct_mixed_untouched mixed_untouched = { init_members }; struct randstruct_mixed_shuffled mixed_shuffled = { init_members }; struct contains_randstruct_untouched contains_untouched = { .untouched = { init_members }, }; struct contains_randstruct_shuffled contains_shuffled = { .shuffled = { init_members }, };#define func_member(x, ignored) \ .x = func_##x, struct randstruct_funcs_untouched funcs_untouched = { DO_MANY_MEMBERS(func_member) }; struct randstruct_funcs_shuffled funcs_shuffled = { DO_MANY_MEMBERS(func_member) };
test_check_init(test, "named", &untouched, &shuffled); test_check_init(test, "unnamed", &untouched, &(struct randstruct_shuffled){ init_members });
test_check_contained_init(test, "named", &contains_untouched, &contains_shuffled); test_check_contained_init(test, "unnamed", &contains_untouched, &(struct contains_randstruct_shuffled){ .shuffled = (struct randstruct_shuffled){ init_members }, });
test_check_contained_init(test, "named", &contains_untouched, &contains_shuffled); test_check_contained_init(test, "unnamed copy", &contains_untouched, &(struct contains_randstruct_shuffled){ /* full struct copy initializer */ .shuffled = shuffled, });
test_check_mixed_init(test, "named", &mixed_untouched, &mixed_shuffled); test_check_mixed_init(test, "unnamed", &mixed_untouched, &(struct randstruct_mixed_shuffled){ init_members });
test_check_funcs_init(test, "named", &funcs_untouched, &funcs_shuffled); test_check_funcs_init(test, "unnamed", &funcs_untouched, &(struct randstruct_funcs_shuffled){ DO_MANY_MEMBERS(func_member) });
#undef func_member#undef init_members}
static int randstruct_test_init(struct kunit *test){ if (!IS_ENABLED(CONFIG_RANDSTRUCT)) kunit_skip(test, "Not built with CONFIG_RANDSTRUCT=y");
return 0;}
static struct kunit_case randstruct_test_cases[] = { KUNIT_CASE(randstruct_layout_same), KUNIT_CASE(randstruct_layout_mixed), KUNIT_CASE(randstruct_layout_fptr), KUNIT_CASE(randstruct_layout_fptr_deep), KUNIT_CASE(randstruct_initializers), {}};
static struct kunit_suite randstruct_test_suite = { .name = "randstruct", .init = randstruct_test_init, .test_cases = randstruct_test_cases,};
kunit_test_suites(&randstruct_test_suite);
MODULE_DESCRIPTION("Test cases for struct randomization");MODULE_LICENSE("GPL");