]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
lib/tests: randstruct: Add deep function pointer layout test
authorKees Cook <kees@kernel.org>
Fri, 2 May 2025 22:41:20 +0000 (15:41 -0700)
committerKees Cook <kees@kernel.org>
Thu, 8 May 2025 16:42:40 +0000 (09:42 -0700)
The recent fix in commit c2ea09b193d2 ("randstruct: gcc-plugin: Remove
bogus void member") has fixed another issue: it was not always detecting
composite structures made only of function pointers and structures of
function pointers. Add a test for this case, and break out the layout
tests since this issue is actually a problem for Clang as well[1].

Link: https://github.com/llvm/llvm-project/issues/138355
Link: https://lore.kernel.org/r/20250502224116.work.591-kees@kernel.org
Signed-off-by: Kees Cook <kees@kernel.org>
lib/tests/randstruct_kunit.c

index c796c8fae263c891c35bdcc52fdc1a6e324f2836..f3a2d63c4cfbe7dce009343796c8a9334c64184a 100644 (file)
@@ -56,7 +56,6 @@ struct randstruct_funcs_untouched {
 struct randstruct_funcs_shuffled {
        DO_MANY_MEMBERS(func_member)
 };
-#undef func_member
 
 #define func_body(x, ignored)                                  \
 static noinline size_t func_##x(int arg)                       \
@@ -103,9 +102,16 @@ struct contains_randstruct_shuffled {
        int after;
 };
 
-static void randstruct_layout(struct kunit *test)
-{
-       int mismatches;
+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))    \
@@ -114,24 +120,66 @@ static void randstruct_layout(struct kunit *test)
                   offsetof(shuffled, x),                       \
                   offsetof(untouched, x));                     \
 
-#define check_pair(outcome, untouched, shuffled)               \
+#define check_pair(outcome, untouched, shuffled, checker...)   \
        mismatches = 0;                                         \
-       DO_MANY_MEMBERS(check_mismatch, untouched, shuffled)    \
+       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");
 
-       check_pair(EXPECT_EQ, struct randstruct_untouched, struct randstruct_untouched)
-       check_pair(EXPECT_GT, struct randstruct_untouched, struct randstruct_shuffled)
-       check_pair(EXPECT_GT, struct randstruct_untouched, struct randstruct_funcs_shuffled)
-       check_pair(EXPECT_GT, struct randstruct_funcs_untouched, struct randstruct_funcs_shuffled)
-       check_pair(EXPECT_GT, struct randstruct_mixed_untouched, struct randstruct_mixed_shuffled)
-#undef check_pair
+static void randstruct_layout_same(struct kunit *test)
+{
+       int mismatches;
 
-#undef check_mismatch
+       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", \
@@ -266,7 +314,10 @@ static int randstruct_test_init(struct kunit *test)
 }
 
 static struct kunit_case randstruct_test_cases[] = {
-       KUNIT_CASE(randstruct_layout),
+       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),
        {}
 };