mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 15:03:53 +02:00
hardening updates for v6.14-rc1-fix1
- Fix regression in GCC 15's initialization of union members -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRSPkdeREjth1dHnSE2KwveOeQkuwUCZ51BJQAKCRA2KwveOeQk u8+jAP0XoKceMYSQkorO8XI2z0NqiKE6zESp/u4n4Y3rqtetUQEA/SXeh9bKrv1G N0m383oVixeztl8wOpwZII9pQHjDngs= =vOzA -----END PGP SIGNATURE----- Merge tag 'hardening-v6.14-rc1-fix1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux Pull hardening fixes from Kees Cook: "This is a fix for the soon to be released GCC 15 which has regressed its initialization of unions when performing explicit initialization (i.e. a general problem, not specifically a hardening problem; we're just carrying the fix). Details in the final patch, Acked by Masahiro, with updated selftests to validate the fix" * tag 'hardening-v6.14-rc1-fix1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: kbuild: Use -fzero-init-padding-bits=all stackinit: Add union initialization to selftests stackinit: Add old-style zero-init syntax to struct tests
This commit is contained in:
commit
73512f2a0b
|
@ -47,10 +47,12 @@ static bool stackinit_range_contains(char *haystack_start, size_t haystack_size,
|
|||
#define DO_NOTHING_TYPE_SCALAR(var_type) var_type
|
||||
#define DO_NOTHING_TYPE_STRING(var_type) void
|
||||
#define DO_NOTHING_TYPE_STRUCT(var_type) void
|
||||
#define DO_NOTHING_TYPE_UNION(var_type) void
|
||||
|
||||
#define DO_NOTHING_RETURN_SCALAR(ptr) *(ptr)
|
||||
#define DO_NOTHING_RETURN_STRING(ptr) /**/
|
||||
#define DO_NOTHING_RETURN_STRUCT(ptr) /**/
|
||||
#define DO_NOTHING_RETURN_UNION(ptr) /**/
|
||||
|
||||
#define DO_NOTHING_CALL_SCALAR(var, name) \
|
||||
(var) = do_nothing_ ## name(&(var))
|
||||
|
@ -58,10 +60,13 @@ static bool stackinit_range_contains(char *haystack_start, size_t haystack_size,
|
|||
do_nothing_ ## name(var)
|
||||
#define DO_NOTHING_CALL_STRUCT(var, name) \
|
||||
do_nothing_ ## name(&(var))
|
||||
#define DO_NOTHING_CALL_UNION(var, name) \
|
||||
do_nothing_ ## name(&(var))
|
||||
|
||||
#define FETCH_ARG_SCALAR(var) &var
|
||||
#define FETCH_ARG_STRING(var) var
|
||||
#define FETCH_ARG_STRUCT(var) &var
|
||||
#define FETCH_ARG_UNION(var) &var
|
||||
|
||||
/*
|
||||
* On m68k, if the leaf function test variable is longer than 8 bytes,
|
||||
|
@ -77,6 +82,7 @@ static bool stackinit_range_contains(char *haystack_start, size_t haystack_size,
|
|||
#define INIT_CLONE_SCALAR /**/
|
||||
#define INIT_CLONE_STRING [FILL_SIZE_STRING]
|
||||
#define INIT_CLONE_STRUCT /**/
|
||||
#define INIT_CLONE_UNION /**/
|
||||
|
||||
#define ZERO_CLONE_SCALAR(zero) memset(&(zero), 0x00, sizeof(zero))
|
||||
#define ZERO_CLONE_STRING(zero) memset(&(zero), 0x00, sizeof(zero))
|
||||
|
@ -92,6 +98,7 @@ static bool stackinit_range_contains(char *haystack_start, size_t haystack_size,
|
|||
zero.three = 0; \
|
||||
zero.four = 0; \
|
||||
} while (0)
|
||||
#define ZERO_CLONE_UNION(zero) ZERO_CLONE_STRUCT(zero)
|
||||
|
||||
#define INIT_SCALAR_none(var_type) /**/
|
||||
#define INIT_SCALAR_zero(var_type) = 0
|
||||
|
@ -101,6 +108,7 @@ static bool stackinit_range_contains(char *haystack_start, size_t haystack_size,
|
|||
|
||||
#define INIT_STRUCT_none(var_type) /**/
|
||||
#define INIT_STRUCT_zero(var_type) = { }
|
||||
#define INIT_STRUCT_old_zero(var_type) = { 0 }
|
||||
|
||||
|
||||
#define __static_partial { .two = 0, }
|
||||
|
@ -146,6 +154,34 @@ static bool stackinit_range_contains(char *haystack_start, size_t haystack_size,
|
|||
#define INIT_STRUCT_assigned_copy(var_type) \
|
||||
; var = *(arg)
|
||||
|
||||
/* Union initialization is the same as structs. */
|
||||
#define INIT_UNION_none(var_type) INIT_STRUCT_none(var_type)
|
||||
#define INIT_UNION_zero(var_type) INIT_STRUCT_zero(var_type)
|
||||
#define INIT_UNION_old_zero(var_type) INIT_STRUCT_old_zero(var_type)
|
||||
|
||||
#define INIT_UNION_static_partial(var_type) \
|
||||
INIT_STRUCT_static_partial(var_type)
|
||||
#define INIT_UNION_static_all(var_type) \
|
||||
INIT_STRUCT_static_all(var_type)
|
||||
#define INIT_UNION_dynamic_partial(var_type) \
|
||||
INIT_STRUCT_dynamic_partial(var_type)
|
||||
#define INIT_UNION_dynamic_all(var_type) \
|
||||
INIT_STRUCT_dynamic_all(var_type)
|
||||
#define INIT_UNION_runtime_partial(var_type) \
|
||||
INIT_STRUCT_runtime_partial(var_type)
|
||||
#define INIT_UNION_runtime_all(var_type) \
|
||||
INIT_STRUCT_runtime_all(var_type)
|
||||
#define INIT_UNION_assigned_static_partial(var_type) \
|
||||
INIT_STRUCT_assigned_static_partial(var_type)
|
||||
#define INIT_UNION_assigned_static_all(var_type) \
|
||||
INIT_STRUCT_assigned_static_all(var_type)
|
||||
#define INIT_UNION_assigned_dynamic_partial(var_type) \
|
||||
INIT_STRUCT_assigned_dynamic_partial(var_type)
|
||||
#define INIT_UNION_assigned_dynamic_all(var_type) \
|
||||
INIT_STRUCT_assigned_dynamic_all(var_type)
|
||||
#define INIT_UNION_assigned_copy(var_type) \
|
||||
INIT_STRUCT_assigned_copy(var_type)
|
||||
|
||||
/*
|
||||
* @name: unique string name for the test
|
||||
* @var_type: type to be tested for zeroing initialization
|
||||
|
@ -294,6 +330,33 @@ struct test_user {
|
|||
unsigned long four;
|
||||
};
|
||||
|
||||
/* No padding: all members are the same size. */
|
||||
union test_same_sizes {
|
||||
unsigned long one;
|
||||
unsigned long two;
|
||||
unsigned long three;
|
||||
unsigned long four;
|
||||
};
|
||||
|
||||
/* Mismatched sizes, with one and two being small */
|
||||
union test_small_start {
|
||||
char one:1;
|
||||
char two;
|
||||
short three;
|
||||
unsigned long four;
|
||||
struct big_struct {
|
||||
unsigned long array[8];
|
||||
} big;
|
||||
};
|
||||
|
||||
/* Mismatched sizes, with one and two being small */
|
||||
union test_small_end {
|
||||
short one;
|
||||
unsigned long two;
|
||||
char three:1;
|
||||
char four;
|
||||
};
|
||||
|
||||
#define ALWAYS_PASS WANT_SUCCESS
|
||||
#define ALWAYS_FAIL XFAIL
|
||||
|
||||
|
@ -332,6 +395,11 @@ struct test_user {
|
|||
struct test_ ## name, STRUCT, init, \
|
||||
xfail)
|
||||
|
||||
#define DEFINE_UNION_TEST(name, init, xfail) \
|
||||
DEFINE_TEST(name ## _ ## init, \
|
||||
union test_ ## name, STRUCT, init, \
|
||||
xfail)
|
||||
|
||||
#define DEFINE_STRUCT_TESTS(init, xfail) \
|
||||
DEFINE_STRUCT_TEST(small_hole, init, xfail); \
|
||||
DEFINE_STRUCT_TEST(big_hole, init, xfail); \
|
||||
|
@ -343,9 +411,22 @@ struct test_user {
|
|||
xfail); \
|
||||
DEFINE_STRUCT_TESTS(base ## _ ## all, xfail)
|
||||
|
||||
#define DEFINE_UNION_INITIALIZER_TESTS(base, xfail) \
|
||||
DEFINE_UNION_TESTS(base ## _ ## partial, \
|
||||
xfail); \
|
||||
DEFINE_UNION_TESTS(base ## _ ## all, xfail)
|
||||
|
||||
#define DEFINE_UNION_TESTS(init, xfail) \
|
||||
DEFINE_UNION_TEST(same_sizes, init, xfail); \
|
||||
DEFINE_UNION_TEST(small_start, init, xfail); \
|
||||
DEFINE_UNION_TEST(small_end, init, xfail);
|
||||
|
||||
/* These should be fully initialized all the time! */
|
||||
DEFINE_SCALAR_TESTS(zero, ALWAYS_PASS);
|
||||
DEFINE_STRUCT_TESTS(zero, ALWAYS_PASS);
|
||||
DEFINE_STRUCT_TESTS(old_zero, ALWAYS_PASS);
|
||||
DEFINE_UNION_TESTS(zero, ALWAYS_PASS);
|
||||
DEFINE_UNION_TESTS(old_zero, ALWAYS_PASS);
|
||||
/* Struct initializers: padding may be left uninitialized. */
|
||||
DEFINE_STRUCT_INITIALIZER_TESTS(static, STRONG_PASS);
|
||||
DEFINE_STRUCT_INITIALIZER_TESTS(dynamic, STRONG_PASS);
|
||||
|
@ -353,6 +434,12 @@ DEFINE_STRUCT_INITIALIZER_TESTS(runtime, STRONG_PASS);
|
|||
DEFINE_STRUCT_INITIALIZER_TESTS(assigned_static, STRONG_PASS);
|
||||
DEFINE_STRUCT_INITIALIZER_TESTS(assigned_dynamic, STRONG_PASS);
|
||||
DEFINE_STRUCT_TESTS(assigned_copy, ALWAYS_FAIL);
|
||||
DEFINE_UNION_INITIALIZER_TESTS(static, STRONG_PASS);
|
||||
DEFINE_UNION_INITIALIZER_TESTS(dynamic, STRONG_PASS);
|
||||
DEFINE_UNION_INITIALIZER_TESTS(runtime, STRONG_PASS);
|
||||
DEFINE_UNION_INITIALIZER_TESTS(assigned_static, STRONG_PASS);
|
||||
DEFINE_UNION_INITIALIZER_TESTS(assigned_dynamic, STRONG_PASS);
|
||||
DEFINE_UNION_TESTS(assigned_copy, ALWAYS_FAIL);
|
||||
/* No initialization without compiler instrumentation. */
|
||||
DEFINE_SCALAR_TESTS(none, STRONG_PASS);
|
||||
DEFINE_STRUCT_TESTS(none, BYREF_PASS);
|
||||
|
@ -436,13 +523,23 @@ DEFINE_TEST_DRIVER(switch_2_none, uint64_t, SCALAR, ALWAYS_FAIL);
|
|||
KUNIT_CASE(test_trailing_hole_ ## init),\
|
||||
KUNIT_CASE(test_packed_ ## init) \
|
||||
|
||||
#define KUNIT_test_unions(init) \
|
||||
KUNIT_CASE(test_same_sizes_ ## init), \
|
||||
KUNIT_CASE(test_small_start_ ## init), \
|
||||
KUNIT_CASE(test_small_end_ ## init) \
|
||||
|
||||
static struct kunit_case stackinit_test_cases[] = {
|
||||
/* These are explicitly initialized and should always pass. */
|
||||
KUNIT_test_scalars(zero),
|
||||
KUNIT_test_structs(zero),
|
||||
KUNIT_test_structs(old_zero),
|
||||
KUNIT_test_unions(zero),
|
||||
KUNIT_test_unions(old_zero),
|
||||
/* Padding here appears to be accidentally always initialized? */
|
||||
KUNIT_test_structs(dynamic_partial),
|
||||
KUNIT_test_structs(assigned_dynamic_partial),
|
||||
KUNIT_test_unions(dynamic_partial),
|
||||
KUNIT_test_unions(assigned_dynamic_partial),
|
||||
/* Padding initialization depends on compiler behaviors. */
|
||||
KUNIT_test_structs(static_partial),
|
||||
KUNIT_test_structs(static_all),
|
||||
|
@ -452,8 +549,17 @@ static struct kunit_case stackinit_test_cases[] = {
|
|||
KUNIT_test_structs(assigned_static_partial),
|
||||
KUNIT_test_structs(assigned_static_all),
|
||||
KUNIT_test_structs(assigned_dynamic_all),
|
||||
KUNIT_test_unions(static_partial),
|
||||
KUNIT_test_unions(static_all),
|
||||
KUNIT_test_unions(dynamic_all),
|
||||
KUNIT_test_unions(runtime_partial),
|
||||
KUNIT_test_unions(runtime_all),
|
||||
KUNIT_test_unions(assigned_static_partial),
|
||||
KUNIT_test_unions(assigned_static_all),
|
||||
KUNIT_test_unions(assigned_dynamic_all),
|
||||
/* Everything fails this since it effectively performs a memcpy(). */
|
||||
KUNIT_test_structs(assigned_copy),
|
||||
KUNIT_test_unions(assigned_copy),
|
||||
/* STRUCTLEAK_BYREF_ALL should cover everything from here down. */
|
||||
KUNIT_test_scalars(none),
|
||||
KUNIT_CASE(test_switch_1_none),
|
||||
|
|
|
@ -77,6 +77,9 @@ KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init)
|
|||
# Warn if there is an enum types mismatch
|
||||
KBUILD_CFLAGS += $(call cc-option,-Wenum-conversion)
|
||||
|
||||
# Explicitly clear padding bits during variable initialization
|
||||
KBUILD_CFLAGS += $(call cc-option,-fzero-init-padding-bits=all)
|
||||
|
||||
KBUILD_CFLAGS += -Wextra
|
||||
KBUILD_CFLAGS += -Wunused
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user