aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@kernel.org>2017-03-29 01:03:56 -0400
committerIngo Molnar <mingo@kernel.org>2017-04-12 03:23:47 -0400
commitea1e34fc366b84e4449b37d86f2222935e29412d (patch)
treeca5dc3065ba800b8ccb593d2af457ed35f971cae
parentd0381c81c2f782fa2131178d11e0cfb23d50d631 (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.c12
-rw-r--r--arch/x86/kernel/kprobes/opt.c5
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 */
276unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr) 279unsigned 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);