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 <[email protected]>
---
 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


Reply via email to