From 8464c25d95b64e14860bf3f480cbd1b14d1cefb9 Mon Sep 17 00:00:00 2001 From: Jessica Yu Date: Wed, 13 Aug 2014 03:10:18 -0700 Subject: [PATCH 1/2] kpatch-patch-hook: fix incorrect old_offsets for loadable modules Fix incorrect old_offsets for loadable modules during sysfs initialization in patch_init. sysfs will be initialized on patch module init regardless of whether or not the module is loaded. func_old_addr_show() will read from func->old_addr, which is initially set to 0; it'll be eventually filled in by the core module. --- kmod/patch/kpatch-patch-hook.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/kmod/patch/kpatch-patch-hook.c b/kmod/patch/kpatch-patch-hook.c index ea68878..b957a61 100644 --- a/kmod/patch/kpatch-patch-hook.c +++ b/kmod/patch/kpatch-patch-hook.c @@ -42,8 +42,7 @@ static struct kobject *functions_kobj; struct kpatch_func_obj { struct kobject kobj; - struct kpatch_patch_func *func; - char name[KSYM_NAME_LEN]; + struct kpatch_func *func; }; static struct kpatch_func_obj **func_objs = NULL; @@ -91,7 +90,7 @@ static ssize_t func_old_addr_show(struct kobject *kobj, struct kpatch_func_obj *func = container_of(kobj, struct kpatch_func_obj, kobj); - return sprintf(buf, "0x%lx\n", func->func->old_offset); + return sprintf(buf, "0x%lx\n", func->func->old_addr); } static ssize_t func_new_addr_show(struct kobject *kobj, @@ -257,7 +256,13 @@ static int patch_make_funcs_list(struct list_head *objects) func->new_addr = p_func->new_addr; func->new_size = p_func->new_size; - func->old_offset = p_func->old_offset; + + /* find correct func->old_offset */ + if (!strcmp("vmlinux", object->name)) + func->old_offset = p_func->old_offset; + else + func->old_addr = 0x0; + func->old_size = p_func->old_size; func->name = p_func->name; func->force = is_func_forced(func->new_addr); @@ -267,13 +272,11 @@ static int patch_make_funcs_list(struct list_head *objects) if (!func_obj) return -ENOMEM; - func_obj->func = p_func; + func_obj->func = func; func_objs[i++] = func_obj; - sprint_symbol_no_offset(func_obj->name, - p_func->old_offset); ret = kobject_add(&func_obj->kobj, functions_kobj, - "%s", func_obj->name); + "%s", func->name); if (ret) return ret; } From 6a69f5f91a89a691288b844ed79b19b786d5c3a7 Mon Sep 17 00:00:00 2001 From: Jessica Yu Date: Thu, 14 Aug 2014 09:23:33 -0700 Subject: [PATCH 2/2] consolidate variables func->old_offset and func->old_addr to just old_addr To reduce redundancy, remove/change the old_offset fields in the kpatch_func and kpatch_patch_func structs to just old_addr. Since old_offset is being used as a placeholder for old_addr, might as well consolidate it to just one variable. --- kmod/core/core.c | 9 ++++----- kmod/core/kpatch.h | 3 +-- kmod/patch/kpatch-patch-hook.c | 3 +-- kmod/patch/kpatch-patch.h | 2 +- kpatch-build/create-diff-object.c | 2 +- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/kmod/core/core.c b/kmod/core/core.c index 8c1bb37..e17234b 100644 --- a/kmod/core/core.c +++ b/kmod/core/core.c @@ -711,16 +711,15 @@ static int kpatch_link_object(struct kpatch_module *kpmod, goto err_unlink; list_for_each_entry(func, &object->funcs, list) { - unsigned long old_addr; /* calculate actual old location */ if (vmlinux) { - old_addr = func->old_offset; ret = kpatch_verify_symbol_match(func->name, - old_addr); + func->old_addr); if (ret) goto err_unlink; } else { + unsigned long old_addr; old_addr = kpatch_find_module_symbol(mod, func->name); if (!old_addr) { pr_err("unable to find symbol '%s' in module '%s\n", @@ -728,14 +727,14 @@ static int kpatch_link_object(struct kpatch_module *kpmod, ret = -EINVAL; goto err_unlink; } + func->old_addr = old_addr; } /* add to ftrace filter and register handler if needed */ - ret = kpatch_ftrace_add_func(old_addr); + ret = kpatch_ftrace_add_func(func->old_addr); if (ret) goto err_unlink; - func->old_addr = old_addr; } return 0; diff --git a/kmod/core/kpatch.h b/kmod/core/kpatch.h index be73593..7523227 100644 --- a/kmod/core/kpatch.h +++ b/kmod/core/kpatch.h @@ -36,7 +36,7 @@ struct kpatch_func { /* public */ unsigned long new_addr; unsigned long new_size; - unsigned long old_offset; + unsigned long old_addr; unsigned long old_size; const char *name; struct list_head list; @@ -44,7 +44,6 @@ struct kpatch_func { /* private */ struct hlist_node node; - unsigned long old_addr; enum kpatch_op op; }; diff --git a/kmod/patch/kpatch-patch-hook.c b/kmod/patch/kpatch-patch-hook.c index b957a61..b901c54 100644 --- a/kmod/patch/kpatch-patch-hook.c +++ b/kmod/patch/kpatch-patch-hook.c @@ -257,9 +257,8 @@ static int patch_make_funcs_list(struct list_head *objects) func->new_addr = p_func->new_addr; func->new_size = p_func->new_size; - /* find correct func->old_offset */ if (!strcmp("vmlinux", object->name)) - func->old_offset = p_func->old_offset; + func->old_addr = p_func->old_addr; else func->old_addr = 0x0; diff --git a/kmod/patch/kpatch-patch.h b/kmod/patch/kpatch-patch.h index 7f013e9..3ce4832 100644 --- a/kmod/patch/kpatch-patch.h +++ b/kmod/patch/kpatch-patch.h @@ -25,7 +25,7 @@ struct kpatch_patch_func { unsigned long new_addr; unsigned long new_size; - unsigned long old_offset; + unsigned long old_addr; unsigned long old_size; char *name; char *objname; diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 52d9e57..849a92e 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -1983,7 +1983,7 @@ void kpatch_create_patches_sections(struct kpatch_elf *kelf, sym->name, result.value, result.size); /* add entry in text section */ - funcs[index].old_offset = result.value; + funcs[index].old_addr = result.value; funcs[index].old_size = result.size; funcs[index].new_size = sym->sym.st_size;