History

objtool/klp: Allow new references to module exports

klp_reloc_needed() returns true for module exports to support late-module patching. However, clone_reloc_klp() unconditionally rejects symbols without a twin (i.e., new references added by the patch), even when the symbol is a known export from Module.symvers. Relax the check: allow new references to exported symbols by only erroring on !twin when there is no export. The export metadata from Module.symvers provides sufficient context to emit the klp-relocation without a twin. For a module export that isn't sufficient on its own though, as the resulting klp relocation will only be resolved at patch-enable time if the exporting module is loaded. If the original (unpatched) module already depends on the exporting module, the dependency is safe: the module loader ensures the dependency is satisfied before the patched module can be loaded, so the klp relocation target will exist. However, if the patch introduces a reference to a module that the original doesn't depend on, there is no such guarantee. The exporting module could be absent or could be unloaded at any time, leading to a relocation failure or use-after-free. So also add a build-time check: when a new symbol reference (no twin) targets a module export, verify that the original module already has at least one UNDEF symbol resolving to that same exporting module. If not, error out with a diagnostic message.

Joe Lawrence committed 3 months ago

Commit 72d76d01 parent 86a69751 file · +33 −2Browse files

Showing the changes to tools/objtool (1 of 1 file). Show all

Unified · Split

tools/objtool/klp-diff.c+33−2
@@ -1295,6 +1295,28 @@ static int convert_reloc_sym(struct elf *elf, struct reloc *reloc) · 1294 unmodified lines
1295 return convert_reloc_secsym_to_sym(elf, reloc);1295 return convert_reloc_secsym_to_sym(elf, reloc);
1296}1296}
1297 1297
1298/*
1299 * Check if the original module already has a dependency on dep_mod, i.e. it
1300 * already references at least one export from that module.
1301 */
1302static bool has_module_dep(struct elfs *e, const char *dep_mod)
1303{
1304 struct symbol *sym;
1305
1306 for_each_sym(e->orig, sym) {
1307 struct export *exp;
1308
1309 if (!is_undef_sym(sym) || is_weak_sym(sym))
1310 continue;
1311
1312 exp = find_export(sym);
1313 if (exp && !strcmp(exp->mod, dep_mod))
1314 return true;
1315 }
1316
1317 return false;
1318}
1319
1298/*1320/*
1299 * Convert a regular relocation to a klp relocation (sort of).1321 * Convert a regular relocation to a klp relocation (sort of).
1300 */1322 */
@@ -1314,8 +1336,17 @@ static int clone_reloc_klp(struct elfs *e, struct reloc *patched_reloc, · 13 unmodified lines
1314 unsigned long sympos;1336 unsigned long sympos;
1315 1337
1316 if (!patched_sym->twin) {1338 if (!patched_sym->twin) {
1317 ERROR("unexpected klp reloc for new symbol %s", patched_sym->name);1339 if (!export) {
1318 return -1;1340 ERROR("unexpected klp reloc for new symbol %s", patched_sym->name);
1341 return -1;
1342 }
1343
1344 if (strcmp(export->mod, "vmlinux") &&
1345 !has_module_dep(e, export->mod)) {
1346 ERROR("%s: new reference to %s (exported by %s) would create an undeclared module dependency",
1347 patched_sym->name, export->sym, export->mod);
1348 return -1;
1349 }
1319 }1350 }
1320 1351
1321 /*1352 /*