From 47a9749d381f02868b4f4bbe1bc841f3f38ac1a1 Mon Sep 17 00:00:00 2001 From: Zhipeng Xie Date: Sun, 22 Nov 2020 21:40:39 +0800 Subject: [PATCH 19/24] Fix relocation not resolved when new functions exported only When no functions changed and new functions exported, kobject is not created, so livepatch will not call klp_init_object and relocation in new functions are not resolved. Signed-off-by: Zhipeng Xie --- kmod/patch/kpatch-patch.h | 4 ++++ kmod/patch/kpatch.lds.S | 6 ++++++ kmod/patch/livepatch-patch-hook.c | 19 +++++++++++++++++++ kpatch-build/create-diff-object.c | 26 ++++++++++++++++++++++++++ 4 files changed, 55 insertions(+) diff --git a/kmod/patch/kpatch-patch.h b/kmod/patch/kpatch-patch.h index 6e39364..33f2056 100644 --- a/kmod/patch/kpatch-patch.h +++ b/kmod/patch/kpatch-patch.h @@ -63,6 +63,10 @@ struct kpatch_post_unpatch_callback { void (*callback)(void *obj); char *objname; }; +struct kpatch_object { + char *objname; +}; extern unsigned long __kpatch_force_funcs[], __kpatch_force_funcs_end[]; +extern struct kpatch_object __kpatch_objects[], __kpatch_objects_end[]; #endif /* _KPATCH_PATCH_H_ */ diff --git a/kmod/patch/kpatch.lds.S b/kmod/patch/kpatch.lds.S index bc5de82..4c4d77b 100644 --- a/kmod/patch/kpatch.lds.S +++ b/kmod/patch/kpatch.lds.S @@ -47,4 +47,10 @@ SECTIONS __kpatch_force_funcs_end = . ; QUAD(0); } + .kpatch.objects : { + __kpatch_objects = . ; + *(.kpatch.objects) + __kpatch_objects_end = . ; + QUAD(0); + } } diff --git a/kmod/patch/livepatch-patch-hook.c b/kmod/patch/livepatch-patch-hook.c index 71439d9..9e56fe3 100644 --- a/kmod/patch/livepatch-patch-hook.c +++ b/kmod/patch/livepatch-patch-hook.c @@ -442,6 +442,22 @@ static int patch_is_func_forced(unsigned long addr) return 0; } +static int add_kpatch_objects(void) +{ + struct kpatch_object *p_kpatch_object; + struct patch_object *object; + + for (p_kpatch_object = __kpatch_objects; + p_kpatch_object < __kpatch_objects_end; + p_kpatch_object++) { + object = patch_find_object_by_name(p_kpatch_object->objname); + if (!object) + return -ENOMEM; + } + + return 0; +} + static int __init patch_init(void) { struct kpatch_patch_func *kfunc; @@ -485,6 +501,9 @@ static int __init patch_init(void) if (ret) goto out; + ret = add_kpatch_objects(); + if (ret) + goto out; /* past this point, only possible return code is -ENOMEM */ ret = -ENOMEM; diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 6b915ae..0bef022 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -2916,6 +2916,27 @@ static void kpatch_create_kpatch_arch_section(struct kpatch_elf *kelf, char *obj karch_sec->sh.sh_size = karch_sec->data->d_size; } +static void kpatch_create_kpatch_object_section(struct kpatch_elf *kelf, char *objname) +{ + struct symbol *strsym; + struct rela *rela; + struct section *kobj_sec; + + kobj_sec = create_section_pair(kelf, ".kpatch.objects", sizeof(struct kpatch_object), 1); + + /* lookup strings symbol */ + strsym = find_symbol_by_name(&kelf->symbols, ".kpatch.strings"); + if (!strsym) + ERROR("can't find .kpatch.strings symbol"); + + /* entries[index].objname */ + ALLOC_LINK(rela, &kobj_sec->rela->relas); + rela->sym = strsym; + rela->type = ABSOLUTE_RELA_TYPE; + rela->addend = offset_of_string(&kelf->strings, objname); + rela->offset = (unsigned int)(offsetof(struct kpatch_object, objname)); +} + static void kpatch_process_special_sections(struct kpatch_elf *kelf, struct lookup_table *lookup) { @@ -3973,6 +3994,11 @@ int main(int argc, char *argv[]) kpatch_create_intermediate_sections(kelf_out, lookup, parent_name, patch_name); kpatch_create_kpatch_arch_section(kelf_out, parent_name); kpatch_create_callbacks_objname_rela(kelf_out, parent_name); + + if (!num_changed && new_globals_exist) { + kpatch_create_kpatch_object_section(kelf_out, parent_name); + } + kpatch_build_strings_section_data(kelf_out); kpatch_create_mcount_sections(kelf_out); -- 2.23.0