[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250427013836.877214-1-kees@kernel.org>
Date: Sat, 26 Apr 2025 18:38:33 -0700
From: Kees Cook <kees@...nel.org>
To: Arnd Bergmann <arnd@...db.de>
Cc: Kees Cook <kees@...nel.org>,
"Dr. David Alan Gilbert" <linux@...blig.org>,
Mark Brown <broonie@...nel.org>,
WangYuli <wangyuli@...ontech.com>,
Mickaël Salaün <mic@...ikod.net>,
Günther Noack <gnoack@...gle.com>,
Bill Wendling <morbo@...gle.com>,
Andrew Morton <akpm@...ux-foundation.org>,
Nathan Chancellor <nathan@...nel.org>,
Nick Desaulniers <nick.desaulniers+lkml@...il.com>,
Justin Stitt <justinstitt@...gle.com>,
Petr Mladek <pmladek@...e.com>,
David Gow <davidgow@...gle.com>,
Rae Moar <rmoar@...gle.com>,
Tamir Duberstein <tamird@...il.com>,
Diego Vieira <diego.daniel.professional@...il.com>,
Luis Chamberlain <mcgrof@...nel.org>,
"Gustavo A. R. Silva" <gustavoars@...nel.org>,
Paul Moore <paul@...l-moore.com>,
James Morris <jmorris@...ei.org>,
"Serge E. Hallyn" <serge@...lyn.com>,
linux-kernel@...r.kernel.org,
llvm@...ts.linux.dev,
linux-hardening@...r.kernel.org,
linux-security-module@...r.kernel.org
Subject: [PATCH 1/3] randstruct: gcc-plugin: Remove bogus void member
When building the randomized replacement tree of struct members, the
randstruct GCC plugin would insert, as the first member, a 0-sized void
member. This appears as though it was done to catch non-designated
("unnamed") static initializers, which wouldn't be stable since they
depend on the original struct layout order.
This was accomplished by having the side-effect of the "void member"
tripping an assert in GCC internals (count_type_elements) if the member
list ever needed to be counted (e.g. for figuring out the order of members
during a non-designated initialization), which would catch impossible type
(void) in the struct:
security/landlock/fs.c: In function ‘hook_file_ioctl_common’:
security/landlock/fs.c:1745:61: internal compiler error: in count_type_elements, at expr.cc:7075
1745 | .u.op = &(struct lsm_ioctlop_audit) {
| ^
static HOST_WIDE_INT
count_type_elements (const_tree type, bool for_ctor_p)
{
switch (TREE_CODE (type))
...
case VOID_TYPE:
default:
gcc_unreachable ();
}
}
However this is a redundant safety measure since randstruct uses the
__designated_initializer attribute both internally and within the
__randomized_layout attribute macro so that this would be enforced
by the compiler directly even when randstruct was not enabled (via
-Wdesignated-init).
A recent change in Landlock ended up tripping the same member counting
routine when using a full-struct copy initializer as part of an anonymous
initializer. This, however, is a false positive as the initializer is
copying between identical structs (and hence identical layouts). The
"path" member is "struct path", a randomized struct, and is being copied
to from another "struct path", the "f_path" member:
landlock_log_denial(landlock_cred(file->f_cred), &(struct landlock_request) {
.type = LANDLOCK_REQUEST_FS_ACCESS,
.audit = {
.type = LSM_AUDIT_DATA_IOCTL_OP,
.u.op = &(struct lsm_ioctlop_audit) {
.path = file->f_path,
.cmd = cmd,
},
},
...
As can be seen with the coming randstruct KUnit test, there appears to
be no behavioral problems with this kind of initialization when the void
member is removed from the randstruct GCC plugin, so remove it.
Reported-by: "Dr. David Alan Gilbert" <linux@...blig.org>
Closes: https://lore.kernel.org/lkml/Z_PRaKx7q70MKgCA@gallifrey/
Reported-by: Mark Brown <broonie@...nel.org>
Closes: https://lore.kernel.org/lkml/20250407-kbuild-disable-gcc-plugins-v1-1-5d46ae583f5e@kernel.org/
Reported-by: WangYuli <wangyuli@...ontech.com>
Closes: https://lore.kernel.org/lkml/337D5D4887277B27+3c677db3-a8b9-47f0-93a4-7809355f1381@uniontech.com/
Fixes: 313dd1b62921 ("gcc-plugins: Add the randstruct plugin")
Signed-off-by: Kees Cook <kees@...nel.org>
---
Cc: "Mickaël Salaün" <mic@...ikod.net>
Cc: Mark Brown <broonie@...nel.org>
Cc: "Günther Noack" <gnoack@...gle.com>
Cc: Arnd Bergmann <arnd@...db.de>
---
scripts/gcc-plugins/randomize_layout_plugin.c | 18 +-----------------
1 file changed, 1 insertion(+), 17 deletions(-)
diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
index 5694df3da2e9..971a1908a8cc 100644
--- a/scripts/gcc-plugins/randomize_layout_plugin.c
+++ b/scripts/gcc-plugins/randomize_layout_plugin.c
@@ -344,29 +344,13 @@ static int relayout_struct(tree type)
shuffle(type, (tree *)newtree, shuffle_length);
- /*
- * set up a bogus anonymous struct field designed to error out on unnamed struct initializers
- * as gcc provides no other way to detect such code
- */
- list = make_node(FIELD_DECL);
- TREE_CHAIN(list) = newtree[0];
- TREE_TYPE(list) = void_type_node;
- DECL_SIZE(list) = bitsize_zero_node;
- DECL_NONADDRESSABLE_P(list) = 1;
- DECL_FIELD_BIT_OFFSET(list) = bitsize_zero_node;
- DECL_SIZE_UNIT(list) = size_zero_node;
- DECL_FIELD_OFFSET(list) = size_zero_node;
- DECL_CONTEXT(list) = type;
- // to satisfy the constify plugin
- TREE_READONLY(list) = 1;
-
for (i = 0; i < num_fields - 1; i++)
TREE_CHAIN(newtree[i]) = newtree[i+1];
TREE_CHAIN(newtree[num_fields - 1]) = NULL_TREE;
main_variant = TYPE_MAIN_VARIANT(type);
for (variant = main_variant; variant; variant = TYPE_NEXT_VARIANT(variant)) {
- TYPE_FIELDS(variant) = list;
+ TYPE_FIELDS(variant) = newtree[0];
TYPE_ATTRIBUTES(variant) = copy_list(TYPE_ATTRIBUTES(variant));
TYPE_ATTRIBUTES(variant) = tree_cons(get_identifier("randomize_performed"), NULL_TREE, TYPE_ATTRIBUTES(variant));
TYPE_ATTRIBUTES(variant) = tree_cons(get_identifier("designated_init"), NULL_TREE, TYPE_ATTRIBUTES(variant));
--
2.34.1
Powered by blists - more mailing lists