Re: [PATCH v3 8/9] objtool/klp: Fix relocations for EXPORT_SYMBOL_FOR_MODULES() symbols

Josh Poimboeuf <[email protected]>
Newsgroups org.kernel.vger.live-patching,org.kernel.vger.linux-kernel
Message-ID <an-_y1AuR2DUkcSu@jpoimboe>
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)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.