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

Dylan Hatch <[email protected]>
Newsgroups org.kernel.vger.live-patching,org.kernel.vger.linux-kernel
Message-ID <CADBMgpz7iWC0=t=_gE-tfvv0mTPq4kg0qQ2zgPH8DVPE6eQ9Kw@mail.gmail.com>
Hi Josh,

On Fri, Aug 7, 2026 at 2:42 PM Josh Poimboeuf <[email protected]> wrote:
>
> 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 <[email protected]>
> Link: https://lore.kernel.org/[email protected]
> Signed-off-by: Josh Poimboeuf <[email protected]>
> ---
>  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/
[2]: https://github.com/dylanbhatch/linux/tree/mod-ns-lp

Thanks,
Dylan
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.