objtool/klp: Fix relocations for EXPORT_SYMBOL_FOR_MODULES() symbols

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: dd590d4d57 ("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
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
Acked-by: Song Liu <song@kernel.org>
Link: https://patch.msgid.link/fe5a00818e06ec613344d41d5944de054fcd8832.1786138493.git.jpoimboe@kernel.org
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
This commit is contained in:
Josh Poimboeuf 2026-08-07 14:37:53 -07:00
parent 72d76d0c18
commit 4cd3cfb8b5

View File

@ -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));
}
@ -1175,11 +1188,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) {
/*