aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-05-28 07:47:10 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2025-05-28 07:47:10 -0700
commit48cfc5791d83b630fd90a1b64a15a6d09c186f99 (patch)
tree5eafeeb38203c56efad2678ac37f751fe355031a /lib
parentMerge tag 'seccomp-v6.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux (diff)
parentRevert "hardening: Disable GCC randstruct for COMPILE_TEST" (diff)
downloadlinux-rng-48cfc5791d83b630fd90a1b64a15a6d09c186f99.tar.xz
linux-rng-48cfc5791d83b630fd90a1b64a15a6d09c186f99.zip
Merge tag 'hardening-v6.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
Pull hardening updates from Kees Cook: - Update overflow helpers to ease refactoring of on-stack flex array instances (Gustavo A. R. Silva, Kees Cook) - lkdtm: Use SLAB_NO_MERGE instead of constructors (Harry Yoo) - Simplify CONFIG_CC_HAS_COUNTED_BY (Jan Hendrik Farr) - Disable u64 usercopy KUnit test on 32-bit SPARC (Thomas Weißschuh) - Add missed designated initializers now exposed by fixed randstruct (Nathan Chancellor, Kees Cook) - Document compilers versions for __builtin_dynamic_object_size - Remove ARM_SSP_PER_TASK GCC plugin - Fix GCC plugin randstruct, add selftests, and restore COMPILE_TEST builds - Kbuild: induce full rebuilds when dependencies change with GCC plugins, the Clang sanitizer .scl file, or the randstruct seed. - Kbuild: Switch from -Wvla to -Wvla-larger-than=1 - Correct several __nonstring uses for -Wunterminated-string-initialization * tag 'hardening-v6.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: (23 commits) Revert "hardening: Disable GCC randstruct for COMPILE_TEST" lib/tests: randstruct: Add deep function pointer layout test lib/tests: Add randstruct KUnit test randstruct: gcc-plugin: Remove bogus void member net: qede: Initialize qede_ll_ops with designated initializer scsi: qedf: Use designated initializer for struct qed_fcoe_cb_ops md/bcache: Mark __nonstring look-up table integer-wrap: Force full rebuild when .scl file changes randstruct: Force full rebuild when seed changes gcc-plugins: Force full rebuild when plugins change kbuild: Switch from -Wvla to -Wvla-larger-than=1 hardening: simplify CONFIG_CC_HAS_COUNTED_BY overflow: Fix direct struct member initialization in _DEFINE_FLEX() kunit/overflow: Add tests for STACK_FLEX_ARRAY_SIZE() helper overflow: Add STACK_FLEX_ARRAY_SIZE() helper input/joystick: magellan: Mark __nonstring look-up table const watchdog: exar: Shorten identity name to fit correctly mod_devicetable: Enlarge the maximum platform_device_id name length overflow: Clarify expectations for getting DEFINE_FLEX variable sizes compiler_types: Identify compiler versions for __builtin_dynamic_object_size ...
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig.debug8
-rw-r--r--lib/Makefile1
-rw-r--r--lib/tests/Makefile1
-rw-r--r--lib/tests/overflow_kunit.c4
-rw-r--r--lib/tests/randstruct_kunit.c334
-rw-r--r--lib/tests/usercopy_kunit.c1
6 files changed, 348 insertions, 1 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index f9051ab610d5..6479cec900c7 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2863,6 +2863,14 @@ config OVERFLOW_KUNIT_TEST
If unsure, say N.
+config RANDSTRUCT_KUNIT_TEST
+ tristate "Test randstruct structure layout randomization at runtime" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ Builds unit tests for the checking CONFIG_RANDSTRUCT=y, which
+ randomizes structure layouts.
+
config STACKINIT_KUNIT_TEST
tristate "Test level of stack variable initialization" if !KUNIT_ALL_TESTS
depends on KUNIT
diff --git a/lib/Makefile b/lib/Makefile
index f07b24ce1b3f..c38582f187dd 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -71,7 +71,6 @@ CFLAGS_test_bitops.o += -Werror
obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o
obj-$(CONFIG_TEST_IDA) += test_ida.o
obj-$(CONFIG_TEST_UBSAN) += test_ubsan.o
-CFLAGS_test_ubsan.o += $(call cc-disable-warning, vla)
CFLAGS_test_ubsan.o += $(call cc-disable-warning, unused-but-set-variable)
UBSAN_SANITIZE_test_ubsan.o := y
obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 5a4794c1826e..56d645014482 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_MEMCPY_KUNIT_TEST) += memcpy_kunit.o
CFLAGS_overflow_kunit.o = $(call cc-disable-warning, tautological-constant-out-of-range-compare)
obj-$(CONFIG_OVERFLOW_KUNIT_TEST) += overflow_kunit.o
obj-$(CONFIG_PRINTF_KUNIT_TEST) += printf_kunit.o
+obj-$(CONFIG_RANDSTRUCT_KUNIT_TEST) += randstruct_kunit.o
obj-$(CONFIG_SCANF_KUNIT_TEST) += scanf_kunit.o
obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o
obj-$(CONFIG_SLUB_KUNIT_TEST) += slub_kunit.o
diff --git a/lib/tests/overflow_kunit.c b/lib/tests/overflow_kunit.c
index 894691b4411a..19cb03b25dc5 100644
--- a/lib/tests/overflow_kunit.c
+++ b/lib/tests/overflow_kunit.c
@@ -1210,6 +1210,10 @@ static void DEFINE_FLEX_test(struct kunit *test)
KUNIT_EXPECT_EQ(test, __struct_size(empty->array), 0);
KUNIT_EXPECT_EQ(test, __member_size(empty->array), 0);
+ KUNIT_EXPECT_EQ(test, STACK_FLEX_ARRAY_SIZE(two, array), 2);
+ KUNIT_EXPECT_EQ(test, STACK_FLEX_ARRAY_SIZE(eight, array), 8);
+ KUNIT_EXPECT_EQ(test, STACK_FLEX_ARRAY_SIZE(empty, array), 0);
+
/* If __counted_by is not being used, array size will have the on-stack size. */
if (!IS_ENABLED(CONFIG_CC_HAS_COUNTED_BY))
array_size_override = 2 * sizeof(s16);
diff --git a/lib/tests/randstruct_kunit.c b/lib/tests/randstruct_kunit.c
new file mode 100644
index 000000000000..f3a2d63c4cfb
--- /dev/null
+++ b/lib/tests/randstruct_kunit.c
@@ -0,0 +1,334 @@
+// 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");
diff --git a/lib/tests/usercopy_kunit.c b/lib/tests/usercopy_kunit.c
index 77fa00a13df7..80f8abe10968 100644
--- a/lib/tests/usercopy_kunit.c
+++ b/lib/tests/usercopy_kunit.c
@@ -27,6 +27,7 @@
!defined(CONFIG_MICROBLAZE) && \
!defined(CONFIG_NIOS2) && \
!defined(CONFIG_PPC32) && \
+ !defined(CONFIG_SPARC32) && \
!defined(CONFIG_SUPERH))
# define TEST_U64
#endif