[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <BN0P110MB2020D78705BB39062BF8D107FD1FA@BN0P110MB2020.NAMP110.PROD.OUTLOOK.COM>
Date: Thu, 25 Sep 2025 17:00:35 +0000
From: "Hill, Steven " <steven.hill@...lins.com>
To: "linux-hardening@...r.kernel.org" <linux-hardening@...r.kernel.org>
CC: Kees Cook <kees@...nel.org>, Masahiro Yamada <masahiroy@...nel.org>
Subject: [RFC] gcc-plugins patch for compiler versioning.
Hello.
Would like to have comments on the attached patch. There could be another
option for checking both gcc and glibc versions. Just wanted comments before
doing anything further. I am not on the mailing list, so please CC: on any
replies. Thank you.
-Steve
>From b1ac0805d70aaa2e1500a071f63c88bcaa76754e Mon Sep 17 00:00:00 2001
From: "Steven J. Hill" <steven.hill@...lins.com>
Date: Tue, 23 Sep 2025 18:21:09 -0500
Subject: [PATCH] gcc-plugins: Relax constraints on plugin compatibility.
The compatibility check for gcc plugins is too inflexible,
and a lot of times wrong. Add ability to let the user choose
how stringent compatibility is.
Signed-off-by: Steven J. Hill <steven.hill@...lins.com>
---
scripts/gcc-plugins/Kconfig | 36 +++++++++++++++++++
scripts/gcc-plugins/Makefile | 15 +++++++-
scripts/gcc-plugins/compare-libc-versions.sh | 28 +++++++++++++++
scripts/gcc-plugins/gcc-common.h | 18 ++++++++++
scripts/gcc-plugins/latent_entropy_plugin.c | 2 +-
scripts/gcc-plugins/randomize_layout_plugin.c | 2 +-
scripts/gcc-plugins/sancov_plugin.c | 2 +-
scripts/gcc-plugins/stackleak_plugin.c | 2 +-
scripts/gcc-plugins/structleak_plugin.c | 2 +-
9 files changed, 101 insertions(+), 6 deletions(-)
create mode 100755 scripts/gcc-plugins/compare-libc-versions.sh
diff --git a/scripts/gcc-plugins/Kconfig b/scripts/gcc-plugins/Kconfig
index 929997fb5e45..626a9200f2a1 100644
--- a/scripts/gcc-plugins/Kconfig
+++ b/scripts/gcc-plugins/Kconfig
@@ -19,6 +19,42 @@ menuconfig GCC_PLUGINS
if GCC_PLUGINS
+choice
+ prompt "Version checking"
+ help
+ Each plugin is required to call plugin_default_version_check() in
+ its init function. This check can at times be too stringent or
+ just plain wrong, especially when cross-compiling. See source file
+ gcc/plugin.cc in the gcc repository for more details. This option
+ allows for the user to choose how stringent the check should be.
+
+ config GCC_PLUGIN_VERSION_CHECK_DEFAULT
+ bool "Default behavior"
+ help
+ Just calls plugin_default_version_check() like before.
+
+ config GCC_PLUGIN_VERSION_CHECK_NONE
+ bool "Disable checking"
+ help
+ Plugins will be built without any incompatibilities
+ being reported to the user.
+
+ config GCC_PLUGIN_VERSION_CHECK_GCC
+ bool "Check only GCC versions"
+ help
+ Compare only the GCC version strings of the host and
+ target compilers.
+
+ config GCC_PLUGIN_VERSION_CHECK_LIBC
+ bool "Check C library versions"
+ help
+ Compares only C library versions. Checks the
+ version strings and the highest library API versions
+ supported in each toolchain. Only glibc-based tools
+ are currently supported.
+
+endchoice
+
config GCC_PLUGIN_SANCOV
bool
# Plugin can be removed once the kernel only supports GCC 6+
diff --git a/scripts/gcc-plugins/Makefile b/scripts/gcc-plugins/Makefile
index 320afd3cf8e8..48d50a3fe362 100644
--- a/scripts/gcc-plugins/Makefile
+++ b/scripts/gcc-plugins/Makefile
@@ -24,6 +24,19 @@ targets += randomize_layout_seed.h
always-y += $(GCC_PLUGIN)
+ifdef CONFIG_GCC_PLUGIN_VERSION_CHECK_DEFAULT
+GCC_PLUGINS_CHECK_VERSION = -DGCC_PLUGIN_VERSION_DEFAULT
+endif
+ifdef CONFIG_GCC_PLUGIN_VERSION_CHECK_NONE
+GCC_PLUGINS_CHECK_VERSION = -DGCC_PLUGIN_VERSION_NONE
+endif
+ifdef CONFIG_GCC_PLUGIN_VERSION_CHECK_GCC
+GCC_PLUGINS_CHECK_VERSION = -DGCC_PLUGIN_VERSION_GCC
+endif
+ifdef CONFIG_GCC_PLUGIN_VERSION_CHECK_LIBC
+GCC_PLUGINS_CHECK_VERSION = $(shell $(srctree)/scripts/gcc-plugins/compare-libc-versions.sh "$(HOSTCXX)" "$(CC)")
+endif
+
GCC_PLUGINS_DIR = $(shell $(CC) -print-file-name=plugin)
plugin_cxxflags = -Wp,-MMD,$(depfile) $(KBUILD_HOSTCXXFLAGS) -fPIC \
@@ -32,7 +45,7 @@ plugin_cxxflags = -Wp,-MMD,$(depfile) $(KBUILD_HOSTCXXFLAGS) -fPIC \
-I $(GCC_PLUGINS_DIR)/include -I $(obj) \
-fno-rtti -fno-exceptions -fasynchronous-unwind-tables \
-ggdb -Wno-narrowing -Wno-unused-variable \
- -Wno-format-diag
+ $(GCC_PLUGINS_CHECK_VERSION) -Wno-format-diag
plugin_ldflags = -shared
diff --git a/scripts/gcc-plugins/compare-libc-versions.sh b/scripts/gcc-plugins/compare-libc-versions.sh
new file mode 100755
index 000000000000..592e501575f2
--- /dev/null
+++ b/scripts/gcc-plugins/compare-libc-versions.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# glibc version comparison script
+
+if test $# -ne 2; then
+ echo "Usage: $0 <hostcxx> <targetcxx>"
+ exit 1
+fi
+
+#
+# Get paths of base C libraries.
+#
+HOSTLIBPATH=$("$1" -print-file-name=libc.so.6)
+TARGLIBPATH=$("$2" -print-file-name=libc.so.6)
+
+#
+# Find the highest library version supported in each.
+#
+HOSTVER=$(readelf -V "$HOSTLIBPATH" | grep "Parent 1: GLIBC_2" | \
+ sed -e's/.*Parent 1: GLIBC_2\.//g' | sort -rn | head -1)
+TARGVER=$(readelf -V "$TARGLIBPATH" | grep "Parent 1: GLIBC_2" | \
+ sed -e's/.*Parent 1: GLIBC_2\.//g' | sort -rn | head -1)
+
+#
+# If we get a match, emit the pre-processor flag.
+#
+[ "${HOSTVER}" = "${TARGVER}" ] && echo "-DGCC_PLUGIN_VERSION_LIBC"
diff --git a/scripts/gcc-plugins/gcc-common.h b/scripts/gcc-plugins/gcc-common.h
index 3222c1070444..5a747895d8e6 100644
--- a/scripts/gcc-plugins/gcc-common.h
+++ b/scripts/gcc-plugins/gcc-common.h
@@ -439,4 +439,22 @@ static inline void debug_gimple_stmt(const_gimple s)
#define last_stmt(x) last_nondebug_stmt(x)
#endif
+static inline int plugin_version_check(struct plugin_gcc_version *plugin_ver,
+ struct plugin_gcc_version *gcc_ver)
+{
+#ifdef GCC_PLUGIN_VERSION_DEFAULT
+ return plugin_default_version_check(plugin_ver, gcc_ver);
+#endif
+#ifdef GCC_PLUGIN_VERSION_NONE
+ return 1;
+#endif
+#ifdef GCC_PLUGIN_VERSION_GCC
+ return (strcmp(plugin_ver->basever, gcc_ver->basever) == 0);
+#endif
+#ifdef GCC_PLUGIN_VERSION_LIBC
+ return 1;
+#endif
+ return 0;
+}
+
#endif
diff --git a/scripts/gcc-plugins/latent_entropy_plugin.c b/scripts/gcc-plugins/latent_entropy_plugin.c
index ff0b192be91f..e1899f16bf22 100644
--- a/scripts/gcc-plugins/latent_entropy_plugin.c
+++ b/scripts/gcc-plugins/latent_entropy_plugin.c
@@ -596,7 +596,7 @@ __visible int plugin_init(struct plugin_name_args *plugin_info,
PASS_INFO(latent_entropy, "optimized", 1, PASS_POS_INSERT_BEFORE);
- if (!plugin_default_version_check(version, &gcc_version)) {
+ if (!plugin_version_check(version, &gcc_version)) {
error(G_("incompatible gcc/plugin versions"));
return 1;
}
diff --git a/scripts/gcc-plugins/randomize_layout_plugin.c b/scripts/gcc-plugins/randomize_layout_plugin.c
index 5694df3da2e9..fd8220c6daeb 100644
--- a/scripts/gcc-plugins/randomize_layout_plugin.c
+++ b/scripts/gcc-plugins/randomize_layout_plugin.c
@@ -851,7 +851,7 @@ __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gc
find_bad_casts_pass_info.ref_pass_instance_number = 1;
find_bad_casts_pass_info.pos_op = PASS_POS_INSERT_AFTER;
- if (!plugin_default_version_check(version, &gcc_version)) {
+ if (!plugin_version_check(version, &gcc_version)) {
error(G_("incompatible gcc/plugin versions"));
return 1;
}
diff --git a/scripts/gcc-plugins/sancov_plugin.c b/scripts/gcc-plugins/sancov_plugin.c
index b76cb9c42cec..78e1e38d3922 100644
--- a/scripts/gcc-plugins/sancov_plugin.c
+++ b/scripts/gcc-plugins/sancov_plugin.c
@@ -106,7 +106,7 @@ __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gc
/* BBs can be split afterwards?? */
PASS_INFO(sancov, "asan", 0, PASS_POS_INSERT_BEFORE);
- if (!plugin_default_version_check(version, &gcc_version)) {
+ if (!plugin_version_check(version, &gcc_version)) {
error(G_("incompatible gcc/plugin versions"));
return 1;
}
diff --git a/scripts/gcc-plugins/stackleak_plugin.c b/scripts/gcc-plugins/stackleak_plugin.c
index d20c47d21ad8..2d3129ad2507 100644
--- a/scripts/gcc-plugins/stackleak_plugin.c
+++ b/scripts/gcc-plugins/stackleak_plugin.c
@@ -560,7 +560,7 @@ __visible int plugin_init(struct plugin_name_args *plugin_info,
*/
PASS_INFO(stackleak_cleanup, "*free_cfg", 1, PASS_POS_INSERT_BEFORE);
- if (!plugin_default_version_check(version, &gcc_version)) {
+ if (!plugin_version_check(version, &gcc_version)) {
error(G_("incompatible gcc/plugin versions"));
return 1;
}
diff --git a/scripts/gcc-plugins/structleak_plugin.c b/scripts/gcc-plugins/structleak_plugin.c
index d8c744233832..7128889979f5 100644
--- a/scripts/gcc-plugins/structleak_plugin.c
+++ b/scripts/gcc-plugins/structleak_plugin.c
@@ -216,7 +216,7 @@ __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gc
PASS_INFO(structleak, "early_optimizations", 1, PASS_POS_INSERT_BEFORE);
- if (!plugin_default_version_check(version, &gcc_version)) {
+ if (!plugin_version_check(version, &gcc_version)) {
error(G_("incompatible gcc/plugin versions"));
return 1;
}
--
2.29.0
Powered by blists - more mailing lists