| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- // 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");
|