When a module is loaded, klp_module_coming() updates all enabled livepatches. If an error occurs, it delegates cleanup to klp_cleanup_module_patches_limited(). However, this cleanup loop skips the partially updated patch, leaving any changes made prior to failure unreverted.
One unhandled failure path occurs inside klp_apply_object_relocs(). On architectures like x86_64, apply_relocate_add() performs a verification step using memcmp() to check that memory contains the expected relocated or zeroed value. If relocations left behind by a failed patch are not cleared, subsequent patch operations or reloads can fail this validation. Introduce klp_write_object_relocs_limited() to unwind and clear only the relocations that were successfully applied before klp_write_object_relocs() encountered an error. There is no need to clear relocations for other objects in the failing patch because klp_module_coming() operates strictly on the specific module being loaded. Reported-by: [email protected] Closes: https://lore.kernel.org/r/[email protected] Signed-off-by: Petr Mladek <[email protected]> --- kernel/livepatch/core.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index a6796cd6b65f..714f97fdd271 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -342,14 +342,17 @@ int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs, secndx, objname, true); } -static int klp_write_object_relocs(struct klp_patch *patch, - struct klp_object *obj, - bool apply) +static int klp_write_object_relocs_limited(struct klp_patch *patch, + struct klp_object *obj, + bool apply, int limit) { int i, ret; struct klp_modinfo *info = patch->mod->klp_info; - for (i = 1; i < info->hdr.e_shnum; i++) { + if (!limit || limit > info->hdr.e_shnum) + limit = info->hdr.e_shnum; + + for (i = 1; i < limit; i++) { Elf_Shdr *sec = info->sechdrs + i; if (!(sec->sh_flags & SHF_RELA_LIVEPATCH)) @@ -359,13 +362,23 @@ static int klp_write_object_relocs(struct klp_patch *patch, info->secstrings, patch->mod->core_kallsyms.strtab, info->symndx, i, obj->name, apply); - if (ret) + if (ret) { + if (apply) + klp_write_object_relocs_limited(patch, obj, false, i); return ret; + } } return 0; } +static int klp_write_object_relocs(struct klp_patch *patch, + struct klp_object *obj, + bool apply) +{ + return klp_write_object_relocs_limited(patch, obj, apply, 0); +} + static int klp_apply_object_relocs(struct klp_patch *patch, struct klp_object *obj) { -- 2.55.0

