History

objtool/klp: Fix vmlinux klp relocations for EXPORT_SYMBOL_FOR_MODULES()

When a module function references a vmlinux symbol which is exported with EXPORT_SYMBOL_FOR_MODULES(), a patch to that function needs to use a klp reloc. Currently, livepatch fails to load such a module: livepatch: invalid access to vmlinux symbol 'get_task_policy' from module-specific livepatch relocation section livepatch: failed to initialize patch 'livepatch_test' for module 'testmod' (-22) livepatch: patch 'livepatch_test' failed for module 'testmod', refusing to load module 'testmod' klp diff puts all klp relocs in __klp_relocs.<patched object>, so post-link names the section .klp.rela.<patched object>.<secname>, which the kernel rejects for vmlinux symbols. Commit 07f14d6af9d77 ("objtool/klp: Fix cross-module klp relocation section naming") changed the meaning of objname in the klp rela section name to be where the referenced symbol is referenced rather than where it lives. That premise only holds for symbols in a module: the relocs get applied when the patched module gets patched, and the module dependency guarantees the referenced module is loaded by then. A vmlinux symbol needs the opposite. It's always resolvable, and it has to be applied when the patch module loads, before the module loader initializes the patch module's special sections, which may reference it. That's why livepatch rejects vmlinux symbols in module-specific sections. Use "vmlinux" as the section objname when the referenced symbol lives in vmlinux. This moves such klp relocs from .klp.rela.kvm..text to .klp.rela.vmlinux..text.

Josh Poimboeuf committed 2 months ago

Commit d8a28601 parent 7df16382 files · +23 −13Browse files

Unified · Split

2 files
  1. tools/objtool/include/objtool/klp.h +3 −2
  2. tools/objtool/klp-diff.c +20 −11
tools/objtool/include/objtool/klp.h+3−2
@@ -20,8 +20,9 @@ · 19 unmodified lines
20 * SHF_RELA_LIVEPATCH, nor does it support having two RELA sections for a20 * SHF_RELA_LIVEPATCH, nor does it support having two RELA sections for a
21 * single PROGBITS section.21 * single PROGBITS section.
22 *22 *
23 * "objname" is the name of the object being patched ("vmlinux" or a module23 * "objname" is the object whose loading gates the relocation: "vmlinux" for
24 * name). post-link uses it to name the resulting24 * references to vmlinux symbols, otherwise the name of the module being
25 * patched. post-link uses it to name the resulting
25 * .klp.rela.objname.section_name sections.26 * .klp.rela.objname.section_name sections.
26 */27 */
27#define KLP_RELOCS_SEC "__klp_relocs"28#define KLP_RELOCS_SEC "__klp_relocs"
tools/objtool/klp-diff.c+20−11
@@ -1344,13 +1344,14 @@ static int clone_reloc_klp(struct elfs *e, struct reloc *patched_reloc, · 1343 unmodified lines
1344 struct section *sec, unsigned long offset,1344 struct section *sec, unsigned long offset,
1345 struct export *export)1345 struct export *export)
1346{1346{
1347 const char *sym_modname, *sym_orig_name, *sec_objname;
1347 struct symbol *patched_sym = patched_reloc->sym;1348 struct symbol *patched_sym = patched_reloc->sym;
1348 s64 addend = reloc_addend(patched_reloc);1349 s64 addend = reloc_addend(patched_reloc);
1349 const char *sym_modname, *sym_orig_name;
1350 static struct section *klp_relocs;
1351 char tombstone_name[SYM_NAME_LEN];1350 char tombstone_name[SYM_NAME_LEN];
1352 struct symbol *sym, *klp_sym;1351 struct symbol *sym, *klp_sym;
1353 unsigned long klp_reloc_off;1352 unsigned long klp_reloc_off;
1353 struct section *klp_relocs;
1354 char sec_name[SEC_NAME_LEN];
1354 char sym_name[SYM_NAME_LEN];1355 char sym_name[SYM_NAME_LEN];
1355 struct klp_reloc klp_reloc;1356 struct klp_reloc klp_reloc;
1356 unsigned long sympos;1357 unsigned long sympos;
@@ -1441,20 +1442,28 @@ static int clone_reloc_klp(struct elfs *e, struct reloc *patched_reloc, · 84 unmodified lines
1441 * This intermediate step is necessary to prevent corruption by the1442 * This intermediate step is necessary to prevent corruption by the
1442 * linker, which doesn't know how to properly handle two rela sections1443 * linker, which doesn't know how to properly handle two rela sections
1443 * applying to the same base section.1444 * applying to the same base section.
1445 *
1446 * The objname decides when the reloc gets applied. A reference to a
1447 * vmlinux symbol goes in the vmlinux section so it gets applied when
1448 * the patch module loads. Everything else goes in the patched
1449 * object's section, applied when the patched module is loaded.
1444 */1450 */
1445 1451
1446 if (!klp_relocs) {1452 if (!strcmp(sym_modname, "vmlinux")) {
1447 const char *objname = find_modname(e);1453 sec_objname = "vmlinux";
1448 char sec_name[SEC_NAME_LEN];1454 } else {
1449 1455 sec_objname = find_modname(e);
1450 if (!objname)1456 if (!sec_objname)
1451 return -1;1457 return -1;
1458 }
1452 1459
1453 /* section format: __klp_relocs.objname */1460 /* section format: __klp_relocs.objname */
1454 if (snprintf_check(sec_name, SEC_NAME_LEN,1461 if (snprintf_check(sec_name, SEC_NAME_LEN,
1455 KLP_RELOCS_SEC ".%s", objname))1462 KLP_RELOCS_SEC ".%s", sec_objname))
1456 return -1;1463 return -1;
1457 1464
1465 klp_relocs = find_section_by_name(e->out, sec_name);
1466 if (!klp_relocs) {
1458 klp_relocs = elf_create_section(e->out, sec_name, 0,1467 klp_relocs = elf_create_section(e->out, sec_name, 0,
1459 0, SHT_PROGBITS, 8, SHF_ALLOC);1468 0, SHT_PROGBITS, 8, SHF_ALLOC);
1460 if (!klp_relocs)1469 if (!klp_relocs)