[PATCH 1/1] objtool/klp-diff: normalize Module.symvers paths to module names
Joe Lawrence <[email protected]> Mon, 13 Jul 2026 17:31:28 -0400
| Newsgroups | org.kernel.vger.live-patching |
|---|---|
| Message-ID | <[email protected]> |
Module.symvers contains build-tree object paths as module identifiers
(e.g., "arch/x86/kvm/kvm") rather than runtime module names ("kvm").
Objtool's clone_reloc_klp() uses this field directly for exported
symbols, while unexported symbols correctly go through __find_modname().
This means that exported symbol relocations may land in a .klp.rela
section named with the build path rather than the module name. That is
a crash waiting to happen: the kernel's livepatch loader silently skips
this relocation because it doesn't match the expected klp_object name.
The unresolved relocation sits in the newly activated code, crashing
when executed.
Normalize export->mod at Module.symvers read time using the same logic
as __find_modname() (refactored into a shared normalize_modname()
helper).
Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffing object files")
Reported-by: Ben Procknow <[email protected]>
Signed-off-by: Joe Lawrence <[email protected]>
---
Note on the fix and existing gotchas for the review bots: The
normalize_modname() helper is a direct refactoring of the pre-existing
loop in __find_modname(). To keep this critical bug fix short and
safe for stable backporting, I've kept the string manipulation logic
identical to what has already been proven stable in objtool.
tools/objtool/klp-diff.c | 42 ++++++++++++++++++++++++++++------------
1 file changed, 30 insertions(+), 12 deletions(-)
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index c2c4e4968bc2..2f3b5e69ab2d 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -83,6 +83,32 @@ static char *escape_str(const char *orig)
return new;
}
+/*
+ * Convert a build-tree object path to a runtime module name: strip
+ * directory components, replace '-' with '_', and remove file
+ * extensions. Examples:
+ *
+ * "arch/x86/kvm/kvm" -> "kvm"
+ * "arch/x86/kvm/kvm-intel" -> "kvm_intel".
+ *
+ * Used by read_exports() to normalize Module.symvers entries and by
+ * __find_modname() as a fallback when .modinfo lacks a "name=" tag.
+ */
+static char *normalize_modname(char *name)
+{
+ for (char *c = name; *c; c++) {
+ if (*c == '/')
+ name = c + 1;
+ else if (*c == '-')
+ *c = '_';
+ else if (*c == '.') {
+ *c = '\0';
+ break;
+ }
+ }
+ return name;
+}
+
static int read_exports(void)
{
const char *symvers = "Module.symvers";
@@ -150,6 +176,9 @@ static int read_exports(void)
return -1;
}
+ if (strcmp(export->mod, "vmlinux"))
+ export->mod = normalize_modname(export->mod);
+
export->sym = strdup(sym);
if (!export->sym) {
ERROR_GLIBC("strdup");
@@ -790,18 +819,7 @@ static const char *__find_modname(struct elfs *e)
return NULL;
}
- for (char *c = name; *c; c++) {
- if (*c == '/')
- name = c + 1;
- else if (*c == '-')
- *c = '_';
- else if (*c == '.') {
- *c = '\0';
- break;
- }
- }
-
- return name;
+ return normalize_modname(name);
}
/* Get the object's module name as defined by the kernel (and klp_object) */
--
2.54.0