On Fri, Aug 14, 2026 at 05:18:19PM -0700, Josh Poimboeuf wrote:
> On Fri, Aug 14, 2026 at 02:05:48PM -0700, Dylan Hatch wrote:
> > Following up on the other thread [1], I noticed that when a patch is
> > touching a module function with a reference to one of these
> > module-exported symbols, the patch/module is rejected because KLP
> > relocs referencing vmlinux symbols are not allowed from
> > module-specific livepatch relocation sections. I was able to reproduce
> > this with a simple module/livepatch combo that depends on one of these
> > symbols [2] (see samples/livepatch/testmod.c and test.patch):
> >
> > root@debian-vm:~$ insmod livepatch-test.ko
> > root@debian-vm:~$ insmod testmod.ko
> > insmod: ERROR: could not insert module testmod.ko: Invalid parameters
> >
> > With dmesg:
> > [ 655.596876] livepatch_test: loading out-of-tree module taints kernel.
> > [ 655.600961] livepatch_test: tainting kernel with TAINT_LIVEPATCH
> > [ 655.605436] livepatch: enabling patch 'livepatch_test'
> > [ 655.609119] livepatch: 'livepatch_test': starting patching transition
> > [ 656.653454] livepatch: 'livepatch_test': patching complete
> > [ 738.777872] livepatch: invalid access to vmlinux symbol
> > 'get_task_policy' from module-specific livepatch relocation section
> > [ 738.784899] livepatch: failed to initialize patch 'livepatch_test'
> > for module 'testmod' (-22)
> > [ 738.790371] livepatch: patch 'livepatch_test' failed for module
> > 'testmod', refusing to load module 'testmod'
> >
> > Do you recommend a strategy for working around this, or is this
> > something that would have to be fixed in the kernel?
>
> Ah, this is another tooling issue, let me work up a patch.
Here is an untested diff, I'll post a proper patch once I get a chance
to test it.
diff --git a/tools/objtool/include/objtool/klp.h
b/tools/objtool/include/objtool/klp.h
index 646d8e1f12eff..c57775d78c71e 100644
--- a/tools/objtool/include/objtool/klp.h
+++ b/tools/objtool/include/objtool/klp.h
@@ -20,8 +20,9 @@
* SHF_RELA_LIVEPATCH, nor does it support having two RELA sections for a
* single PROGBITS section.
*
- * "objname" is the name of the object being patched ("vmlinux" or a module
- * name). post-link uses it to name the resulting
+ * "objname" is the object whose loading gates the relocation: "vmlinux" for
+ * references to vmlinux symbols, otherwise the name of the module being
+ * patched. post-link uses it to name the resulting
* .klp.rela.objname.section_name sections.
*/
#define KLP_RELOCS_SEC "__klp_relocs"
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index a66049e0726a6..16681a76f13d0 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1344,13 +1344,14 @@ static int clone_reloc_klp(struct elfs *e, struct reloc
*patched_reloc,
struct section *sec, unsigned long offset,
struct export *export)
{
+ const char *sym_modname, *sym_orig_name, *sec_objname;
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;
char tombstone_name[SYM_NAME_LEN];
struct symbol *sym, *klp_sym;
unsigned long klp_reloc_off;
+ struct section *klp_relocs;
+ char sec_name[SEC_NAME_LEN];
char sym_name[SYM_NAME_LEN];
struct klp_reloc klp_reloc;
unsigned long sympos;
@@ -1441,20 +1442,28 @@ static int clone_reloc_klp(struct elfs *e, struct reloc
*patched_reloc,
* This intermediate step is necessary to prevent corruption by the
* linker, which doesn't know how to properly handle two rela sections
* applying to the same base section.
+ *
+ * The objname decides when the reloc gets applied. A reference to a
+ * vmlinux symbol goes in the vmlinux section so it gets applied when
+ * the patch module loads. Everything else goes in the patched
+ * object's section, applied when the patched module is loaded.
*/
+ if (!strcmp(sym_modname, "vmlinux")) {
+ sec_objname = "vmlinux";
+ } else {
+ sec_objname = find_modname(e);
+ if (!sec_objname)
+ return -1;
+ }
+
+ /* section format: __klp_relocs.objname */
+ if (snprintf_check(sec_name, SEC_NAME_LEN,
+ KLP_RELOCS_SEC ".%s", sec_objname))
+ return -1;
+
+ klp_relocs = find_section_by_name(e->out, sec_name);
if (!klp_relocs) {
- const char *objname = find_modname(e);
- char sec_name[SEC_NAME_LEN];
-
- if (!objname)
- return -1;
-
- /* section format: __klp_relocs.objname */
- if (snprintf_check(sec_name, SEC_NAME_LEN,
- KLP_RELOCS_SEC ".%s", objname))
- return -1;
-
klp_relocs = elf_create_section(e->out, sec_name, 0,
0, SHT_PROGBITS, 8, SHF_ALLOC);
if (!klp_relocs)