aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2015-12-03 17:33:26 -0500
committerJiri Kosina <jkosina@suse.cz>2015-12-04 16:51:07 -0500
commitb56b36ee6751abe7fb3890681e86fc8de2122953 (patch)
treeb95a1d26730cf2389214e303199c25bc160134c9
parentfc284d631894d8673d229fad92762b66c9875cab (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.c25
-rw-r--r--kernel/livepatch/core.c16
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 @@
38int klp_write_module_reloc(struct module *mod, unsigned long type, 36int 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,
232static int klp_write_object_relocations(struct module *pmod, 233static 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; 275out:
276 module_enable_ro(pmod);
277 return ret;
272} 278}
273 279
274static void notrace klp_ftrace_handler(unsigned long ip, 280static void notrace klp_ftrace_handler(unsigned long ip,