[PATCH] objtool/klp: Fix missed changes to same-named symbol references
From: Longjun Luo <hidden>
Date: 2026-09-10 08:52:50
Also in:
lkml
Subsystem:
objtool, the rest · Maintainers:
Josh Poimboeuf, Peter Zijlstra, Linus Torvalds
Hashing symbol references by demangled_name alone can miss target
changes while the instruction or data bytes and normalized relocation
offsets remain unchanged. This occurs when:
- A global function moves between files and calls a same-named static
function with a different implementation.
- A function's call target changes from a global function to a
same-named static function, without moving the caller.
- A data object, such as an ops structure, changes its function pointer
from a global function to a same-named static function.
These false negatives can silently omit changed functions from a
livepatch or fail to reject changed data.
Hash referenced symbols as (filename, demangled_name) instead. Use an
empty filename when no FILE is associated, and include both terminating
NULs to delimit the fields.
Verified all three cases with klp-build on x86-64: the function cases
produce livepatch modules with the expected target relocations, and the
data case is rejected. Hand-built unchanged-input controls produce
identical checksums. Module loading was not tested.
Fixes: 0d83da43b1e1 ("objtool/klp: Add --checksum option to generate per-function checksums")
Assisted-by: LLM
Signed-off-by: Longjun Luo <redacted>
---
tools/objtool/include/objtool/checksum.h | 27 ++++++++++++++++++++++++
tools/objtool/klp-checksum.c | 13 ++++--------
2 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/tools/objtool/include/objtool/checksum.h b/tools/objtool/include/objtool/checksum.h
index d46293f54716..1834d34dfd47 100644
--- a/tools/objtool/include/objtool/checksum.h
+++ b/tools/objtool/include/objtool/checksum.h@@ -20,6 +20,16 @@ static inline void __checksum_update(struct symbol *sym, const void *data, XXH3_64bits_update(sym->csum.state, data, size); } +/* Include FILE identity to distinguish same-named local targets. */ +static inline void __checksum_update_symbol_identity(struct symbol *sym, + struct symbol *target) +{ + const char *file_name = target->file ? target->file->name : ""; + + __checksum_update(sym, file_name, strlen(file_name) + 1); + __checksum_update(sym, target->demangled_name, strlen(target->demangled_name) + 1); +} + static inline void __checksum_update_insn(struct symbol *sym, struct instruction *insn, const void *data, size_t size)
@@ -28,6 +38,14 @@ static inline void __checksum_update_insn(struct symbol *sym, dbg_checksum_insn(sym, insn, XXH3_64bits_digest(sym->csum.state)); } +static inline void __checksum_update_symbol(struct symbol *sym, + struct instruction *insn, + struct symbol *target) +{ + __checksum_update_symbol_identity(sym, target); + dbg_checksum_insn(sym, insn, XXH3_64bits_digest(sym->csum.state)); +} + static inline void __checksum_update_object(struct symbol *sym, unsigned long offset, const char *what, const void *data,
@@ -38,6 +56,15 @@ static inline void __checksum_update_object(struct symbol *sym, dbg_checksum_object(sym, offset, what, XXH3_64bits_digest(sym->csum.state)); } +static inline void __checksum_update_object_symbol(struct symbol *sym, + unsigned long offset, + struct symbol *target) +{ + __checksum_update(sym, &offset, sizeof(offset)); + __checksum_update_symbol_identity(sym, target); + dbg_checksum_object(sym, offset, "reloc name", XXH3_64bits_digest(sym->csum.state)); +} + static inline void checksum_finish(struct symbol *sym) { if (sym && sym->csum.state) {
diff --git a/tools/objtool/klp-checksum.c b/tools/objtool/klp-checksum.c
index b8e47f28997e..3da3fe11bf76 100644
--- a/tools/objtool/klp-checksum.c
+++ b/tools/objtool/klp-checksum.c@@ -85,8 +85,7 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func, __checksum_update_insn(func, insn, buf, len); if (call_dest) { - __checksum_update_insn(func, insn, call_dest->demangled_name, - strlen(call_dest->demangled_name)); + __checksum_update_symbol(func, insn, call_dest); } else if (jump_dest) { struct symbol *dest_sym;
@@ -102,8 +101,7 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func, if (!dest_sym) goto alts; - __checksum_update_insn(func, insn, dest_sym->demangled_name, - strlen(dest_sym->demangled_name)); + __checksum_update_symbol(func, insn, dest_sym); offset = jump_dest->offset - dest_sym->offset; __checksum_update_insn(func, insn, &offset, sizeof(offset));
@@ -137,8 +135,7 @@ static void checksum_update_insn(struct objtool_file *file, struct symbol *func, offset -= sym->offset; } - __checksum_update_insn(func, insn, sym->demangled_name, - strlen(sym->demangled_name)); + __checksum_update_symbol(func, insn, sym); __checksum_update_insn(func, insn, &offset, sizeof(offset)); alts:
@@ -206,9 +203,7 @@ static void checksum_update_object(struct objtool_file *file, struct symbol *sym offset -= target->offset; } - __checksum_update_object(sym, sym_offset, "reloc name", - target->demangled_name, - strlen(target->demangled_name)); + __checksum_update_object_symbol(sym, sym_offset, target); __checksum_update_object(sym, sym_offset, "reloc addend", &offset, sizeof(offset)); }
base-commit: 50d05c7c76c96b90462f24debacca971d2e86713 -- 2.43.7