diff options
author | Petr Mladek <pmladek@suse.com> | 2019-01-09 07:43:19 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2019-01-11 14:51:23 -0500 |
commit | 19514910d021c93c7823ec32067e6b7dea224f0f (patch) | |
tree | 3df053de0eb62fec2557e24bd807cae328d4f21a | |
parent | 1686cc1a31f45a3fd090e5d0c6fce777422e13fa (diff) |
livepatch: Change unsigned long old_addr -> void *old_func in struct klp_func
The address of the to be patched function and new function is stored
in struct klp_func as:
void *new_func;
unsigned long old_addr;
The different naming scheme and type are derived from the way
the addresses are set. @old_addr is assigned at runtime using
kallsyms-based search. @new_func is statically initialized,
for example:
static struct klp_func funcs[] = {
{
.old_name = "cmdline_proc_show",
.new_func = livepatch_cmdline_proc_show,
}, { }
};
This patch changes unsigned long old_addr -> void *old_func. It removes
some confusion when these address are later used in the code. It is
motivated by a followup patch that adds special NOP struct klp_func
where we want to assign func->new_func = func->old_addr respectively
func->new_func = func->old_func.
This patch does not modify the existing behavior.
Suggested-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Acked-by: Miroslav Benes <mbenes@suse.cz>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
Acked-by: Alice Ferrazzi <alice.ferrazzi@gmail.com>
Acked-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r-- | include/linux/livepatch.h | 4 | ||||
-rw-r--r-- | kernel/livepatch/core.c | 6 | ||||
-rw-r--r-- | kernel/livepatch/patch.c | 18 | ||||
-rw-r--r-- | kernel/livepatch/patch.h | 4 | ||||
-rw-r--r-- | kernel/livepatch/transition.c | 4 |
5 files changed, 19 insertions, 17 deletions
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h index aec44b1d9582..634e13876380 100644 --- a/include/linux/livepatch.h +++ b/include/linux/livepatch.h | |||
@@ -40,7 +40,7 @@ | |||
40 | * @new_func: pointer to the patched function code | 40 | * @new_func: pointer to the patched function code |
41 | * @old_sympos: a hint indicating which symbol position the old function | 41 | * @old_sympos: a hint indicating which symbol position the old function |
42 | * can be found (optional) | 42 | * can be found (optional) |
43 | * @old_addr: the address of the function being patched | 43 | * @old_func: pointer to the function being patched |
44 | * @kobj: kobject for sysfs resources | 44 | * @kobj: kobject for sysfs resources |
45 | * @stack_node: list node for klp_ops func_stack list | 45 | * @stack_node: list node for klp_ops func_stack list |
46 | * @old_size: size of the old function | 46 | * @old_size: size of the old function |
@@ -77,7 +77,7 @@ struct klp_func { | |||
77 | unsigned long old_sympos; | 77 | unsigned long old_sympos; |
78 | 78 | ||
79 | /* internal */ | 79 | /* internal */ |
80 | unsigned long old_addr; | 80 | void *old_func; |
81 | struct kobject kobj; | 81 | struct kobject kobj; |
82 | struct list_head stack_node; | 82 | struct list_head stack_node; |
83 | unsigned long old_size, new_size; | 83 | unsigned long old_size, new_size; |
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 5b77a7314e01..cb59c7fb94cb 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c | |||
@@ -648,7 +648,7 @@ static void klp_free_object_loaded(struct klp_object *obj) | |||
648 | obj->mod = NULL; | 648 | obj->mod = NULL; |
649 | 649 | ||
650 | klp_for_each_func(obj, func) | 650 | klp_for_each_func(obj, func) |
651 | func->old_addr = 0; | 651 | func->old_func = NULL; |
652 | } | 652 | } |
653 | 653 | ||
654 | /* | 654 | /* |
@@ -721,11 +721,11 @@ static int klp_init_object_loaded(struct klp_patch *patch, | |||
721 | klp_for_each_func(obj, func) { | 721 | klp_for_each_func(obj, func) { |
722 | ret = klp_find_object_symbol(obj->name, func->old_name, | 722 | ret = klp_find_object_symbol(obj->name, func->old_name, |
723 | func->old_sympos, | 723 | func->old_sympos, |
724 | &func->old_addr); | 724 | (unsigned long *)&func->old_func); |
725 | if (ret) | 725 | if (ret) |
726 | return ret; | 726 | return ret; |
727 | 727 | ||
728 | ret = kallsyms_lookup_size_offset(func->old_addr, | 728 | ret = kallsyms_lookup_size_offset((unsigned long)func->old_func, |
729 | &func->old_size, NULL); | 729 | &func->old_size, NULL); |
730 | if (!ret) { | 730 | if (!ret) { |
731 | pr_err("kallsyms size lookup failed for '%s'\n", | 731 | pr_err("kallsyms size lookup failed for '%s'\n", |
diff --git a/kernel/livepatch/patch.c b/kernel/livepatch/patch.c index 7702cb4064fc..825022d70912 100644 --- a/kernel/livepatch/patch.c +++ b/kernel/livepatch/patch.c | |||
@@ -34,7 +34,7 @@ | |||
34 | 34 | ||
35 | static LIST_HEAD(klp_ops); | 35 | static LIST_HEAD(klp_ops); |
36 | 36 | ||
37 | struct klp_ops *klp_find_ops(unsigned long old_addr) | 37 | struct klp_ops *klp_find_ops(void *old_func) |
38 | { | 38 | { |
39 | struct klp_ops *ops; | 39 | struct klp_ops *ops; |
40 | struct klp_func *func; | 40 | struct klp_func *func; |
@@ -42,7 +42,7 @@ struct klp_ops *klp_find_ops(unsigned long old_addr) | |||
42 | list_for_each_entry(ops, &klp_ops, node) { | 42 | list_for_each_entry(ops, &klp_ops, node) { |
43 | func = list_first_entry(&ops->func_stack, struct klp_func, | 43 | func = list_first_entry(&ops->func_stack, struct klp_func, |
44 | stack_node); | 44 | stack_node); |
45 | if (func->old_addr == old_addr) | 45 | if (func->old_func == old_func) |
46 | return ops; | 46 | return ops; |
47 | } | 47 | } |
48 | 48 | ||
@@ -142,17 +142,18 @@ static void klp_unpatch_func(struct klp_func *func) | |||
142 | 142 | ||
143 | if (WARN_ON(!func->patched)) | 143 | if (WARN_ON(!func->patched)) |
144 | return; | 144 | return; |
145 | if (WARN_ON(!func->old_addr)) | 145 | if (WARN_ON(!func->old_func)) |
146 | return; | 146 | return; |
147 | 147 | ||
148 | ops = klp_find_ops(func->old_addr); | 148 | ops = klp_find_ops(func->old_func); |
149 | if (WARN_ON(!ops)) | 149 | if (WARN_ON(!ops)) |
150 | return; | 150 | return; |
151 | 151 | ||
152 | if (list_is_singular(&ops->func_stack)) { | 152 | if (list_is_singular(&ops->func_stack)) { |
153 | unsigned long ftrace_loc; | 153 | unsigned long ftrace_loc; |
154 | 154 | ||
155 | ftrace_loc = klp_get_ftrace_location(func->old_addr); | 155 | ftrace_loc = |
156 | klp_get_ftrace_location((unsigned long)func->old_func); | ||
156 | if (WARN_ON(!ftrace_loc)) | 157 | if (WARN_ON(!ftrace_loc)) |
157 | return; | 158 | return; |
158 | 159 | ||
@@ -174,17 +175,18 @@ static int klp_patch_func(struct klp_func *func) | |||
174 | struct klp_ops *ops; | 175 | struct klp_ops *ops; |
175 | int ret; | 176 | int ret; |
176 | 177 | ||
177 | if (WARN_ON(!func->old_addr)) | 178 | if (WARN_ON(!func->old_func)) |
178 | return -EINVAL; | 179 | return -EINVAL; |
179 | 180 | ||
180 | if (WARN_ON(func->patched)) | 181 | if (WARN_ON(func->patched)) |
181 | return -EINVAL; | 182 | return -EINVAL; |
182 | 183 | ||
183 | ops = klp_find_ops(func->old_addr); | 184 | ops = klp_find_ops(func->old_func); |
184 | if (!ops) { | 185 | if (!ops) { |
185 | unsigned long ftrace_loc; | 186 | unsigned long ftrace_loc; |
186 | 187 | ||
187 | ftrace_loc = klp_get_ftrace_location(func->old_addr); | 188 | ftrace_loc = |
189 | klp_get_ftrace_location((unsigned long)func->old_func); | ||
188 | if (!ftrace_loc) { | 190 | if (!ftrace_loc) { |
189 | pr_err("failed to find location for function '%s'\n", | 191 | pr_err("failed to find location for function '%s'\n", |
190 | func->old_name); | 192 | func->old_name); |
diff --git a/kernel/livepatch/patch.h b/kernel/livepatch/patch.h index e72d8250d04b..a9b16e513656 100644 --- a/kernel/livepatch/patch.h +++ b/kernel/livepatch/patch.h | |||
@@ -10,7 +10,7 @@ | |||
10 | * struct klp_ops - structure for tracking registered ftrace ops structs | 10 | * struct klp_ops - structure for tracking registered ftrace ops structs |
11 | * | 11 | * |
12 | * A single ftrace_ops is shared between all enabled replacement functions | 12 | * A single ftrace_ops is shared between all enabled replacement functions |
13 | * (klp_func structs) which have the same old_addr. This allows the switch | 13 | * (klp_func structs) which have the same old_func. This allows the switch |
14 | * between function versions to happen instantaneously by updating the klp_ops | 14 | * between function versions to happen instantaneously by updating the klp_ops |
15 | * struct's func_stack list. The winner is the klp_func at the top of the | 15 | * struct's func_stack list. The winner is the klp_func at the top of the |
16 | * func_stack (front of the list). | 16 | * func_stack (front of the list). |
@@ -25,7 +25,7 @@ struct klp_ops { | |||
25 | struct ftrace_ops fops; | 25 | struct ftrace_ops fops; |
26 | }; | 26 | }; |
27 | 27 | ||
28 | struct klp_ops *klp_find_ops(unsigned long old_addr); | 28 | struct klp_ops *klp_find_ops(void *old_func); |
29 | 29 | ||
30 | int klp_patch_object(struct klp_object *obj); | 30 | int klp_patch_object(struct klp_object *obj); |
31 | void klp_unpatch_object(struct klp_object *obj); | 31 | void klp_unpatch_object(struct klp_object *obj); |
diff --git a/kernel/livepatch/transition.c b/kernel/livepatch/transition.c index 304d5eb8a98c..f27a378ad5e1 100644 --- a/kernel/livepatch/transition.c +++ b/kernel/livepatch/transition.c | |||
@@ -224,11 +224,11 @@ static int klp_check_stack_func(struct klp_func *func, | |||
224 | * Check for the to-be-patched function | 224 | * Check for the to-be-patched function |
225 | * (the previous func). | 225 | * (the previous func). |
226 | */ | 226 | */ |
227 | ops = klp_find_ops(func->old_addr); | 227 | ops = klp_find_ops(func->old_func); |
228 | 228 | ||
229 | if (list_is_singular(&ops->func_stack)) { | 229 | if (list_is_singular(&ops->func_stack)) { |
230 | /* original function */ | 230 | /* original function */ |
231 | func_addr = func->old_addr; | 231 | func_addr = (unsigned long)func->old_func; |
232 | func_size = func->old_size; | 232 | func_size = func->old_size; |
233 | } else { | 233 | } else { |
234 | /* previously patched function */ | 234 | /* previously patched function */ |