[tip: objtool/core] objtool/klp: Add test for static locals which must not be correlated

From: tip-bot2 for Song Liu

Date: Fri Sep 18 2026 - 06:29:50 EST


The following commit has been merged into the objtool/core branch of tip:

Commit-ID: 34bc77c4c640c8de199c71d81f603218551485ef
Gitweb: https://git.kernel.org/tip/34bc77c4c640c8de199c71d81f603218551485ef
Author: Song Liu <song@xxxxxxxxxx>
AuthorDate: Wed, 16 Sep 2026 11:43:32 -07:00
Committer: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
CommitterDate: Wed, 16 Sep 2026 17:21:45 -07:00

objtool/klp: Add test for static locals which must not be correlated

Most static locals have to be correlated so the patched code keeps using
the running kernel's copy. Two kinds must not: anything in .data..once,
the flag behind WARN_ONCE and friends, and the well-known names the kernel
generates for per-instance things (__warned, __key, __func__).

Sharing a .data..once flag means a patch inherits "already warned" from
before it was applied, and the warning it was meant to surface never fires.

The fixture deliberately does not name its .data..once variable __warned:
the name rule would then catch it and the section rule would go untested.
gcc spells these <var>.<id> and Clang <func>.<var>, so both are covered.

This tests the behavior of commit ff529864e738 ("objtool/klp: Fix
.data..once static local non-correlation") and commit 84c304a534b8
("objtool/klp: Fix is_uncorrelated_static_local() for Clang").

Assisted-by: Claude:claude-opus-4
Based-on-test-by: Joe Lawrence <joe.lawrence@xxxxxxxxxx>
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@xxxxxxxxxx>
Link: https://patch.msgid.link/20260916184351.2720310-40-song@xxxxxxxxxx
Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
---
tools/objtool/tests/generic/fixtures/static_local_uncorrelated.c | 41 +++++++++++++++++++++++++++++++++++++++++
tools/objtool/tests/generic/test-static-local-uncorrelated.sh | 41 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 82 insertions(+)
create mode 100644 tools/objtool/tests/generic/fixtures/static_local_uncorrelated.c
create mode 100755 tools/objtool/tests/generic/test-static-local-uncorrelated.sh

diff --git a/tools/objtool/tests/generic/fixtures/static_local_uncorrelated.c b/tools/objtool/tests/generic/fixtures/static_local_uncorrelated.c
new file mode 100644
index 0000000..cb4cdd7
--- /dev/null
+++ b/tools/objtool/tests/generic/fixtures/static_local_uncorrelated.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Static locals of three kinds, in one patched function.
+ *
+ * Most static locals must be correlated, so the patched code keeps using the
+ * running kernel's copy. Two kinds must not:
+ *
+ * - anything in .data..once, the flag behind WARN_ONCE and friends. Sharing
+ * it would mean a patch inherits "already warned" from before the patch.
+ * - the well-known names the kernel generates for such things (__warned,
+ * __key, __func__, ...), which are per-instance by nature. gcc names them
+ * <var>.<id> and Clang <func>.<var>, so both spellings have to be caught.
+ */
+
+static const char __modinfo[]
+ __attribute__((section(".modinfo"), used, aligned(1))) = "\0name=vmlinux";
+
+int target(int x)
+{
+ /*
+ * A .data..once variable whose name is *not* on the list below, so
+ * only the section can disqualify it. Naming it __warned would let
+ * the name rule catch it and the section rule go untested.
+ */
+ static int once_flag __attribute__((section(".data..once")));
+ /* a never-correlate name, in an ordinary section */
+ static int __key;
+ /* and one that must be correlated */
+ static int ordinary;
+
+ if (!once_flag)
+ once_flag = 1;
+ __key += x;
+ ordinary += x;
+
+#ifdef PATCHED
+ return __key + ordinary + once_flag + 2;
+#else
+ return __key + ordinary + once_flag + 1;
+#endif
+}
diff --git a/tools/objtool/tests/generic/test-static-local-uncorrelated.sh b/tools/objtool/tests/generic/test-static-local-uncorrelated.sh
new file mode 100755
index 0000000..d771158
--- /dev/null
+++ b/tools/objtool/tests/generic/test-static-local-uncorrelated.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Some static locals must not be correlated with their counterparts in the
+# running kernel; the patched code has to use a fresh copy instead.
+#
+# .data..once holds the "have we warned yet" flags behind WARN_ONCE. Correlate
+# one and the patched function inherits the flag from before the patch, so the
+# warning the patch was written to produce never fires. The same goes for the
+# names the kernel generates for per-instance state -- __warned, __key,
+# __func__ and friends.
+#
+# Both directions matter, so an ordinary static local is here too: a rule that
+# refuses to correlate anything would pass a test that only checks the
+# refusals.
+
+. "$(dirname "$0")/../lib.sh"
+
+setup
+build_pair static_local_uncorrelated.c
+run_diff
+
+# Compilers mangle static locals differently -- gcc gives __key.1, Clang
+# target.__key -- so match on the base name.
+
+# Correlated: referenced through a klp symbol, pointing at the kernel's copy.
+out_symbols | grep -q '\.klp\.sym\..*ordinary' ||
+ fail "ordinary static local was not correlated"
+
+# Not correlated: no klp symbol, and a copy cloned into the patch instead.
+out_symbols | grep -q '\.klp\.sym\..*__key' &&
+ fail "__key was correlated; it must use a fresh copy"
+# .sbss/.sdata on the architectures with a small-data area.
+out_sections | grep -qE '\.s?(bss|data)[^ ]*__key' ||
+ fail "__key was neither correlated nor cloned"
+
+out_symbols | grep -q '\.klp\.sym\..*once_flag' &&
+ fail ".data..once variable was correlated; it must use a fresh copy"
+assert_section '.data..once'
+
+pass "per-instance static locals cloned, ordinary ones correlated"