[PATCH 1/4] objtool/klp: use patched module name for klp-relocation section naming
Joe Lawrence <[email protected]> Mon, 20 Jul 2026 10:56:55 -0400
| Newsgroups | org.kernel.vger.live-patching |
|---|---|
| Message-ID | <[email protected]> |
Documentation/livepatch/module-elf-format.rst states (and the kernel
currently implements) that the name of a livepatch relocation section
must conform to the following format:
.klp.rela.objname.section_name
where "objname" determines when the kernel applies the relocations in
this section (i.e., when the "objname" module loads). This allows
relocations not only for currently loaded kernel objects (like vmlinux
and loaded device drivers), but also for lazy resolution to facilitate
late-module livepatching (for modules loaded after the livepatch).
Previously, objtool's KLP post-link step derived the "objname" from the
klp symbol name, which encoded where the symbol *lives* rather than
which module is being *patched*. This broke cross-module references
(e.g., can_isotp.ko calling can_rx_unregister() from can.ko),
incorrectly placing them in the .klp.rela.can..text section instead of
.klp.rela.can_isotp..text.
Fix this by adding an 'obj_name' field to the intermediate 'klp_reloc'
struct. klp-diff populates this field using find_modname(), and
klp-post-link reads it directly to generate the .klp.rela section name.
As a result, each relocation correctly carries its own target module,
regardless of where the referenced symbol originates.
Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffing object files")
Signed-off-by: Joe Lawrence <[email protected]>
---
tools/objtool/include/objtool/klp.h | 1 +
tools/objtool/klp-diff.c | 66 +++++++++++++++++++++++------
tools/objtool/klp-post-link.c | 20 +++++----
3 files changed, 65 insertions(+), 22 deletions(-)
diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/objtool/klp.h
index 6f60cf05db86..bf655b2a7590 100644
--- a/tools/objtool/include/objtool/klp.h
+++ b/tools/objtool/include/objtool/klp.h
@@ -26,6 +26,7 @@
struct klp_reloc {
void *offset;
void *sym;
+ void *obj_name;
u32 type;
};
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 819f6f167e8c..c5cc54ee562e 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1518,13 +1518,15 @@ static int clone_reloc_klp(struct elfs *e, struct reloc *patched_reloc,
{
struct symbol *patched_sym = patched_reloc->sym;
s64 addend = reloc_addend(patched_reloc);
- const char *sym_modname, *sym_orig_name;
- static struct section *klp_relocs;
+ const char *sym_modname, *sym_orig_name, *patched_modname;
+ static struct section *klp_relocs, *klp_strs;
+ static struct symbol *klp_strs_sym;
struct symbol *sym, *klp_sym;
unsigned long klp_reloc_off;
char sym_name[SYM_NAME_LEN];
struct klp_reloc klp_reloc;
unsigned long sympos;
+ s64 str_addend;
if (!patched_sym->twin) {
ERROR("unexpected klp reloc for new symbol %s", patched_sym->name);
@@ -1603,6 +1605,24 @@ static int clone_reloc_klp(struct elfs *e, struct reloc *patched_reloc,
0, SHT_PROGBITS, 8, SHF_ALLOC);
if (!klp_relocs)
return -1;
+
+ klp_strs = find_section_by_name(e->out, KLP_STRINGS_SEC);
+ if (!klp_strs) {
+ klp_strs = elf_create_section(e->out, KLP_STRINGS_SEC,
+ 0, 0, SHT_PROGBITS, 1,
+ SHF_ALLOC | SHF_STRINGS | SHF_MERGE);
+ if (!klp_strs)
+ return -1;
+ if (elf_add_string(e->out, klp_strs, "") == -1)
+ return -1;
+ }
+
+ klp_strs_sym = klp_strs->sym;
+ if (!klp_strs_sym) {
+ klp_strs_sym = elf_create_section_symbol(e->out, klp_strs);
+ if (!klp_strs_sym)
+ return -1;
+ }
}
klp_reloc_off = sec_size(klp_relocs);
@@ -1627,6 +1647,20 @@ static int clone_reloc_klp(struct elfs *e, struct reloc *patched_reloc,
klp_sym, addend, R_ABS64))
return -1;
+ /* klp_reloc.obj_name: the patched module, for .klp.rela section naming */
+ patched_modname = find_modname(e);
+ if (!patched_modname)
+ return -1;
+
+ str_addend = elf_add_string(e->out, klp_strs, patched_modname);
+ if (str_addend == -1)
+ return -1;
+
+ if (!elf_create_reloc(e->out, klp_relocs,
+ klp_reloc_off + offsetof(struct klp_reloc, obj_name),
+ klp_strs_sym, str_addend, R_ABS64))
+ return -1;
+
return 0;
}
@@ -2177,18 +2211,24 @@ static int create_klp_sections(struct elfs *e)
if (!funcs_sym)
return -1;
- str_sec = elf_create_section(e->out, KLP_STRINGS_SEC, 0, 0,
- SHT_PROGBITS, 1,
- SHF_ALLOC | SHF_STRINGS | SHF_MERGE);
- if (!str_sec)
- return -1;
-
- if (elf_add_string(e->out, str_sec, "") == -1)
- return -1;
+ /* clone_reloc_klp() may have already created this section */
+ str_sec = find_section_by_name(e->out, KLP_STRINGS_SEC);
+ if (!str_sec) {
+ str_sec = elf_create_section(e->out, KLP_STRINGS_SEC, 0, 0,
+ SHT_PROGBITS, 1,
+ SHF_ALLOC | SHF_STRINGS | SHF_MERGE);
+ if (!str_sec)
+ return -1;
+ if (elf_add_string(e->out, str_sec, "") == -1)
+ return -1;
+ }
- str_sym = elf_create_section_symbol(e->out, str_sec);
- if (!str_sym)
- return -1;
+ str_sym = str_sec->sym;
+ if (!str_sym) {
+ str_sym = elf_create_section_symbol(e->out, str_sec);
+ if (!str_sym)
+ return -1;
+ }
/* allocate klp_object_ext */
obj_data = elf_add_data(e->out, obj_sec, NULL, obj_size, true);
diff --git a/tools/objtool/klp-post-link.c b/tools/objtool/klp-post-link.c
index c013e39957b1..141b0a46ca52 100644
--- a/tools/objtool/klp-post-link.c
+++ b/tools/objtool/klp-post-link.c
@@ -39,7 +39,7 @@ static int fix_klp_relocs(struct elf *elf)
struct section *sec, *tmp, *klp_rsec;
unsigned long offset;
struct reloc *reloc;
- char sym_modname[64];
+ const char *sec_objname;
char rsec_name[SEC_NAME_LEN];
u64 addend;
struct symbol *sym, *klp_sym;
@@ -73,18 +73,20 @@ static int fix_klp_relocs(struct elf *elf)
klp_sym = reloc->sym;
addend = reloc_addend(reloc);
- /* symbol format: .klp.sym.modname.sym_name,sympos */
- if (sscanf(klp_sym->name + strlen(KLP_SYM_PREFIX), "%55[^.]", sym_modname) != 1)
- ERROR("can't find modname in klp symbol '%s'", klp_sym->name);
-
- /*
- * Create the KLP rela:
- */
+ /* klp_reloc.obj_name: the patched module name */
+ reloc = find_reloc_by_dest(elf, klp_relocs,
+ klp_reloc_off + offsetof(struct klp_reloc, obj_name));
+ if (!reloc) {
+ ERROR("malformed " KLP_RELOCS_SEC " section");
+ return -1;
+ }
+ sec_objname = (const char *)reloc->sym->sec->data->d_buf +
+ reloc_addend(reloc);
/* section format: .klp.rela.sec_objname.section_name */
if (snprintf_check(rsec_name, SEC_NAME_LEN,
KLP_RELOC_SEC_PREFIX "%s.%s",
- sym_modname, sec->name))
+ sec_objname, sec->name))
return -1;
klp_rsec = find_section_by_name(elf, rsec_name);
--
2.54.0