diff options
author | Masami Hiramatsu <mhiramat@kernel.org> | 2017-05-25 06:38:17 -0400 |
---|---|---|
committer | Steven Rostedt (VMware) <rostedt@goodmis.org> | 2017-05-26 22:37:00 -0400 |
commit | c93f5cf571e7795f97d49ef51b766cf25e328545 (patch) | |
tree | dbe64f0e9bf5a26ece23376aa925a8c13be817fe | |
parent | f9797c2f20c0160edd718aa467101f3301e57e59 (diff) |
kprobes/x86: Fix to set RWX bits correctly before releasing trampoline
Fix kprobes to set(recover) RWX bits correctly on trampoline
buffer before releasing it. Releasing readonly page to
module_memfree() crash the kernel.
Without this fix, if kprobes user register a bunch of kprobes
in function body (since kprobes on function entry usually
use ftrace) and unregister it, kernel hits a BUG and crash.
Link: http://lkml.kernel.org/r/149570868652.3518.14120169373590420503.stgit@devbox
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Fixes: d0381c81c2f7 ("kprobes/x86: Set kprobes pages read-only")
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
-rw-r--r-- | arch/x86/kernel/kprobes/core.c | 9 | ||||
-rw-r--r-- | kernel/kprobes.c | 2 |
2 files changed, 10 insertions, 1 deletions
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 5b2bbfbb3712..6b877807598b 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c | |||
@@ -52,6 +52,7 @@ | |||
52 | #include <linux/ftrace.h> | 52 | #include <linux/ftrace.h> |
53 | #include <linux/frame.h> | 53 | #include <linux/frame.h> |
54 | #include <linux/kasan.h> | 54 | #include <linux/kasan.h> |
55 | #include <linux/moduleloader.h> | ||
55 | 56 | ||
56 | #include <asm/text-patching.h> | 57 | #include <asm/text-patching.h> |
57 | #include <asm/cacheflush.h> | 58 | #include <asm/cacheflush.h> |
@@ -417,6 +418,14 @@ static void prepare_boost(struct kprobe *p, struct insn *insn) | |||
417 | } | 418 | } |
418 | } | 419 | } |
419 | 420 | ||
421 | /* Recover page to RW mode before releasing it */ | ||
422 | void free_insn_page(void *page) | ||
423 | { | ||
424 | set_memory_nx((unsigned long)page & PAGE_MASK, 1); | ||
425 | set_memory_rw((unsigned long)page & PAGE_MASK, 1); | ||
426 | module_memfree(page); | ||
427 | } | ||
428 | |||
420 | static int arch_copy_kprobe(struct kprobe *p) | 429 | static int arch_copy_kprobe(struct kprobe *p) |
421 | { | 430 | { |
422 | struct insn insn; | 431 | struct insn insn; |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 2d2d3a568e4e..adfe3b4cfe05 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -122,7 +122,7 @@ static void *alloc_insn_page(void) | |||
122 | return module_alloc(PAGE_SIZE); | 122 | return module_alloc(PAGE_SIZE); |
123 | } | 123 | } |
124 | 124 | ||
125 | static void free_insn_page(void *page) | 125 | void __weak free_insn_page(void *page) |
126 | { | 126 | { |
127 | module_memfree(page); | 127 | module_memfree(page); |
128 | } | 128 | } |