diff options
author | Josh Poimboeuf <jpoimboe@redhat.com> | 2015-12-03 17:33:26 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2015-12-04 16:51:07 -0500 |
commit | b56b36ee6751abe7fb3890681e86fc8de2122953 (patch) | |
tree | b95a1d26730cf2389214e303199c25bc160134c9 | |
parent | fc284d631894d8673d229fad92762b66c9875cab (diff) |
livepatch: Cleanup module page permission changes
Calling set_memory_rw() and set_memory_ro() for every iteration of the
loop in klp_write_object_relocations() is messy, inefficient, and
error-prone.
Change all the read-only pages to read-write before the loop and convert
them back to read-only again afterwards.
Suggested-by: Miroslav Benes <mbenes@suse.cz>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r-- | arch/x86/kernel/livepatch.c | 25 | ||||
-rw-r--r-- | kernel/livepatch/core.c | 16 |
2 files changed, 13 insertions, 28 deletions
diff --git a/arch/x86/kernel/livepatch.c b/arch/x86/kernel/livepatch.c index bcc06e82a593..92fc1a51f994 100644 --- a/arch/x86/kernel/livepatch.c +++ b/arch/x86/kernel/livepatch.c | |||
@@ -20,8 +20,6 @@ | |||
20 | 20 | ||
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/uaccess.h> | 22 | #include <linux/uaccess.h> |
23 | #include <asm/cacheflush.h> | ||
24 | #include <asm/page_types.h> | ||
25 | #include <asm/elf.h> | 23 | #include <asm/elf.h> |
26 | #include <asm/livepatch.h> | 24 | #include <asm/livepatch.h> |
27 | 25 | ||
@@ -38,8 +36,7 @@ | |||
38 | int klp_write_module_reloc(struct module *mod, unsigned long type, | 36 | int klp_write_module_reloc(struct module *mod, unsigned long type, |
39 | unsigned long loc, unsigned long value) | 37 | unsigned long loc, unsigned long value) |
40 | { | 38 | { |
41 | int ret, numpages, size = 4; | 39 | size_t size = 4; |
42 | bool readonly; | ||
43 | unsigned long val; | 40 | unsigned long val; |
44 | unsigned long core = (unsigned long)mod->core_layout.base; | 41 | unsigned long core = (unsigned long)mod->core_layout.base; |
45 | unsigned long core_size = mod->core_layout.size; | 42 | unsigned long core_size = mod->core_layout.size; |
@@ -69,23 +66,5 @@ int klp_write_module_reloc(struct module *mod, unsigned long type, | |||
69 | /* loc does not point to any symbol inside the module */ | 66 | /* loc does not point to any symbol inside the module */ |
70 | return -EINVAL; | 67 | return -EINVAL; |
71 | 68 | ||
72 | readonly = false; | 69 | return probe_kernel_write((void *)loc, &val, size); |
73 | |||
74 | #ifdef CONFIG_DEBUG_SET_MODULE_RONX | ||
75 | if (loc < core + mod->core_layout.ro_size) | ||
76 | readonly = true; | ||
77 | #endif | ||
78 | |||
79 | /* determine if the relocation spans a page boundary */ | ||
80 | numpages = ((loc & PAGE_MASK) == ((loc + size) & PAGE_MASK)) ? 1 : 2; | ||
81 | |||
82 | if (readonly) | ||
83 | set_memory_rw(loc & PAGE_MASK, numpages); | ||
84 | |||
85 | ret = probe_kernel_write((void *)loc, &val, size); | ||
86 | |||
87 | if (readonly) | ||
88 | set_memory_ro(loc & PAGE_MASK, numpages); | ||
89 | |||
90 | return ret; | ||
91 | } | 70 | } |
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 94893e844e44..bc2c85c064c1 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/list.h> | 28 | #include <linux/list.h> |
29 | #include <linux/kallsyms.h> | 29 | #include <linux/kallsyms.h> |
30 | #include <linux/livepatch.h> | 30 | #include <linux/livepatch.h> |
31 | #include <asm/cacheflush.h> | ||
31 | 32 | ||
32 | /** | 33 | /** |
33 | * struct klp_ops - structure for tracking registered ftrace ops structs | 34 | * struct klp_ops - structure for tracking registered ftrace ops structs |
@@ -232,7 +233,7 @@ static int klp_find_external_symbol(struct module *pmod, const char *name, | |||
232 | static int klp_write_object_relocations(struct module *pmod, | 233 | static int klp_write_object_relocations(struct module *pmod, |
233 | struct klp_object *obj) | 234 | struct klp_object *obj) |
234 | { | 235 | { |
235 | int ret; | 236 | int ret = 0; |
236 | unsigned long val; | 237 | unsigned long val; |
237 | struct klp_reloc *reloc; | 238 | struct klp_reloc *reloc; |
238 | 239 | ||
@@ -242,13 +243,16 @@ static int klp_write_object_relocations(struct module *pmod, | |||
242 | if (WARN_ON(!obj->relocs)) | 243 | if (WARN_ON(!obj->relocs)) |
243 | return -EINVAL; | 244 | return -EINVAL; |
244 | 245 | ||
246 | module_disable_ro(pmod); | ||
247 | |||
245 | for (reloc = obj->relocs; reloc->name; reloc++) { | 248 | for (reloc = obj->relocs; reloc->name; reloc++) { |
246 | /* discover the address of the referenced symbol */ | 249 | /* discover the address of the referenced symbol */ |
247 | if (reloc->external) { | 250 | if (reloc->external) { |
248 | if (reloc->sympos > 0) { | 251 | if (reloc->sympos > 0) { |
249 | pr_err("non-zero sympos for external reloc symbol '%s' is not supported\n", | 252 | pr_err("non-zero sympos for external reloc symbol '%s' is not supported\n", |
250 | reloc->name); | 253 | reloc->name); |
251 | return -EINVAL; | 254 | ret = -EINVAL; |
255 | goto out; | ||
252 | } | 256 | } |
253 | ret = klp_find_external_symbol(pmod, reloc->name, &val); | 257 | ret = klp_find_external_symbol(pmod, reloc->name, &val); |
254 | } else | 258 | } else |
@@ -257,18 +261,20 @@ static int klp_write_object_relocations(struct module *pmod, | |||
257 | reloc->sympos, | 261 | reloc->sympos, |
258 | &val); | 262 | &val); |
259 | if (ret) | 263 | if (ret) |
260 | return ret; | 264 | goto out; |
261 | 265 | ||
262 | ret = klp_write_module_reloc(pmod, reloc->type, reloc->loc, | 266 | ret = klp_write_module_reloc(pmod, reloc->type, reloc->loc, |
263 | val + reloc->addend); | 267 | val + reloc->addend); |
264 | if (ret) { | 268 | if (ret) { |
265 | pr_err("relocation failed for symbol '%s' at 0x%016lx (%d)\n", | 269 | pr_err("relocation failed for symbol '%s' at 0x%016lx (%d)\n", |
266 | reloc->name, val, ret); | 270 | reloc->name, val, ret); |
267 | return ret; | 271 | goto out; |
268 | } | 272 | } |
269 | } | 273 | } |
270 | 274 | ||
271 | return 0; | 275 | out: |
276 | module_enable_ro(pmod); | ||
277 | return ret; | ||
272 | } | 278 | } |
273 | 279 | ||
274 | static void notrace klp_ftrace_handler(unsigned long ip, | 280 | static void notrace klp_ftrace_handler(unsigned long ip, |