diff options
author | Masami Hiramatsu <mhiramat@kernel.org> | 2017-03-29 01:03:56 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2017-04-12 03:23:47 -0400 |
commit | ea1e34fc366b84e4449b37d86f2222935e29412d (patch) | |
tree | ca5dc3065ba800b8ccb593d2af457ed35f971cae | |
parent | d0381c81c2f782fa2131178d11e0cfb23d50d631 (diff) |
kprobes/x86: Use probe_kernel_read() instead of memcpy()
Use probe_kernel_read() for avoiding unexpected faults while
copying kernel text in __recover_probed_insn(),
__recover_optprobed_insn() and __copy_instruction().
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: David S . Miller <davem@davemloft.net>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ye Xiaolong <xiaolong.ye@intel.com>
Link: http://lkml.kernel.org/r/149076382624.22469.10091613887942958518.stgit@devbox
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/kernel/kprobes/core.c | 12 | ||||
-rw-r--r-- | arch/x86/kernel/kprobes/opt.c | 5 |
2 files changed, 13 insertions, 4 deletions
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 0dc24e6cdd1e..722f54440e7e 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c | |||
@@ -259,7 +259,10 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr) | |||
259 | * Fortunately, we know that the original code is the ideal 5-byte | 259 | * Fortunately, we know that the original code is the ideal 5-byte |
260 | * long NOP. | 260 | * long NOP. |
261 | */ | 261 | */ |
262 | memcpy(buf, (void *)addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); | 262 | if (probe_kernel_read(buf, (void *)addr, |
263 | MAX_INSN_SIZE * sizeof(kprobe_opcode_t))) | ||
264 | return 0UL; | ||
265 | |||
263 | if (faddr) | 266 | if (faddr) |
264 | memcpy(buf, ideal_nops[NOP_ATOMIC5], 5); | 267 | memcpy(buf, ideal_nops[NOP_ATOMIC5], 5); |
265 | else | 268 | else |
@@ -271,7 +274,7 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr) | |||
271 | * Recover the probed instruction at addr for further analysis. | 274 | * Recover the probed instruction at addr for further analysis. |
272 | * Caller must lock kprobes by kprobe_mutex, or disable preemption | 275 | * Caller must lock kprobes by kprobe_mutex, or disable preemption |
273 | * for preventing to release referencing kprobes. | 276 | * for preventing to release referencing kprobes. |
274 | * Returns zero if the instruction can not get recovered. | 277 | * Returns zero if the instruction can not get recovered (or access failed). |
275 | */ | 278 | */ |
276 | unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr) | 279 | unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr) |
277 | { | 280 | { |
@@ -365,7 +368,10 @@ int __copy_instruction(u8 *dest, u8 *src) | |||
365 | /* Another subsystem puts a breakpoint, failed to recover */ | 368 | /* Another subsystem puts a breakpoint, failed to recover */ |
366 | if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION) | 369 | if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION) |
367 | return 0; | 370 | return 0; |
368 | memcpy(dest, insn.kaddr, length); | 371 | |
372 | /* This can access kernel text if given address is not recovered */ | ||
373 | if (kernel_probe_read(dest, insn.kaddr, length)) | ||
374 | return 0; | ||
369 | 375 | ||
370 | #ifdef CONFIG_X86_64 | 376 | #ifdef CONFIG_X86_64 |
371 | /* Only x86_64 has RIP relative instructions */ | 377 | /* Only x86_64 has RIP relative instructions */ |
diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index b121037739e4..5b5233441d30 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c | |||
@@ -65,7 +65,10 @@ found: | |||
65 | * overwritten by jump destination address. In this case, original | 65 | * overwritten by jump destination address. In this case, original |
66 | * bytes must be recovered from op->optinsn.copied_insn buffer. | 66 | * bytes must be recovered from op->optinsn.copied_insn buffer. |
67 | */ | 67 | */ |
68 | memcpy(buf, (void *)addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); | 68 | if (probe_kernel_read(buf, (void *)addr, |
69 | MAX_INSN_SIZE * sizeof(kprobe_opcode_t))) | ||
70 | return 0UL; | ||
71 | |||
69 | if (addr == (unsigned long)kp->addr) { | 72 | if (addr == (unsigned long)kp->addr) { |
70 | buf[0] = kp->opcode; | 73 | buf[0] = kp->opcode; |
71 | memcpy(buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE); | 74 | memcpy(buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE); |