Thread (19 messages) flat view 19 messages, 5 authors, 5d ago

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

From: Dylan Hatch <hidden>
Date: 2026-08-14 21:06:01
Also in: lkml

Hi Josh,

On Fri, Aug 7, 2026 at 2:42 PM Josh Poimboeuf [off-list ref] wrote:
quoted hunk ↗ jump to hunk
EXPORT_SYMBOL_FOR_MODULES() puts a symbol in a "module:<names>"
namespace, which the module loader grants access to by matching the
importing module's name against that list.

klp_reloc_needed() only creates a klp reloc for module-owned exports; a
vmlinux export gets a normal reloc.  For a vmlinux symbol exported with
EXPORT_SYMBOL_FOR_MODULES(), using a normal reloc results in a modpost
failure in klp-build:

  ERROR: modpost: module livepatch-foo uses symbol mpol_shared_policy_lookup from namespace module:kvm, but does not import it.

And the modpost error is correct: even with that error removed, the
patch module would fail to load:

  livepatch_foo: module uses symbol (mpol_shared_policy_lookup) from namespace module:kvm, but does not import it.
  livepatch_foo: Unknown symbol mpol_shared_policy_lookup (err -22)

Treat it like an unexported symbol by using a klp reloc.

Note this only affects "module:" namespaces.  Ordinary namespaced
exports continue to work with normal relocs thanks to copy_import_ns(),
which propagates the patched object's import_ns tags to the patch
module.

Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffing object files")
Reported-by: Joe Lawrence <joe.lawrence@redhat.com>
Link: https://lore.kernel.org/6a6608f4-0a05-4d75-8b7f-edddfac9c5d4@redhat.com (local)
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
 tools/objtool/klp-diff.c | 28 +++++++++++++++++++++++-----
 1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 6d34186d8b24c..0f135b74a5b0c 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -30,7 +30,9 @@ struct elfs {

 struct export {
        struct hlist_node hash;
-       char *mod, *sym;
+       char *mod;
+       char *sym;
+       bool mod_ns;
 };

 bool debug, debug_correlate, debug_clone;
@@ -135,7 +137,7 @@ static int read_exports(void)
        }

        while (fgets(line, 1024, file)) {
-               char *sym, *mod, *type;
+               char *sym, *mod, *type, *namespace;
                struct export *export;

                sym = strchr(line, '\t');
@@ -162,6 +164,14 @@ static int read_exports(void)

                *type++ = '\0';

+               namespace = strchr(type, '\t');
+               if (!namespace) {
+                       ERROR("malformed Module.symvers (namespace) at line %d", line_num);
+                       return -1;
+               }
+
+               *namespace++ = '\0';
+
                if (*sym == '\0' || *mod == '\0') {
                        ERROR("malformed Module.symvers at line %d", line_num);
                        return -1;
@@ -188,6 +198,9 @@ static int read_exports(void)
                        return -1;
                }

+               /* EXPORT_SYMBOL_FOR_MODULES() */
+               export->mod_ns = strstarts(namespace, "module:");
+
                hash_add(exports, &export->hash, str_hash(sym));
        }
@@ -1174,11 +1187,16 @@ static bool klp_reloc_needed(struct reloc *patched_reloc)
         * clusterfunk that is late module patching, the patch module is
         * allowed to be loaded before any modules it depends on.
         *
-        * If exported by vmlinux, a normal reloc will do.
+        * If exported by vmlinux to all modules, a normal reloc will do.
         */
        export = find_export(patched_sym);
-       if (export)
-               return strcmp(export->mod, "vmlinux");
+       if (export) {
+               if (strcmp(export->mod, "vmlinux"))
+                       return true;
+
+               /* EXPORT_SYMBOL_FOR_MODULES() gets a klp reloc */
+               return export->mod_ns;
+       }

        if (!patched_sym->twin) {
                /*
--
2.54.0
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?

Refs:

[1]: https://lore.kernel.org/all/CADBMgpyY6R_YmEqhZSw=88-Bfkv9=s-N-x1siE1uPAgH_fTURw@mail.gmail.com/ (local)
[2]: https://github.com/dylanbhatch/linux/tree/mod-ns-lp

Thanks,
Dylan
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help