[PATCH] objtool/klp: Fix missed changes to same-named symbol references

From: Longjun Luo

Date: Thu Sep 10 2026 - 05:06:11 EST


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 <luolongjuna@xxxxxxxxx>
---
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