Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea1e34fc authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Ingo Molnar
Browse files

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: default avatarMasami 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: default avatarIngo Molnar <mingo@kernel.org>
parent d0381c81
Loading
Loading
Loading
Loading
+9 −3
Original line number Original line Diff line number Diff line
@@ -259,7 +259,10 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
	 * Fortunately, we know that the original code is the ideal 5-byte
	 * Fortunately, we know that the original code is the ideal 5-byte
	 * long NOP.
	 * long NOP.
	 */
	 */
	memcpy(buf, (void *)addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
	if (probe_kernel_read(buf, (void *)addr,
		MAX_INSN_SIZE * sizeof(kprobe_opcode_t)))
		return 0UL;

	if (faddr)
	if (faddr)
		memcpy(buf, ideal_nops[NOP_ATOMIC5], 5);
		memcpy(buf, ideal_nops[NOP_ATOMIC5], 5);
	else
	else
@@ -271,7 +274,7 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
 * Recover the probed instruction at addr for further analysis.
 * Recover the probed instruction at addr for further analysis.
 * Caller must lock kprobes by kprobe_mutex, or disable preemption
 * Caller must lock kprobes by kprobe_mutex, or disable preemption
 * for preventing to release referencing kprobes.
 * for preventing to release referencing kprobes.
 * Returns zero if the instruction can not get recovered.
 * Returns zero if the instruction can not get recovered (or access failed).
 */
 */
unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
{
{
@@ -365,7 +368,10 @@ int __copy_instruction(u8 *dest, u8 *src)
	/* Another subsystem puts a breakpoint, failed to recover */
	/* Another subsystem puts a breakpoint, failed to recover */
	if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION)
	if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION)
		return 0;
		return 0;
	memcpy(dest, insn.kaddr, length);

	/* This can access kernel text if given address is not recovered */
	if (kernel_probe_read(dest, insn.kaddr, length))
		return 0;


#ifdef CONFIG_X86_64
#ifdef CONFIG_X86_64
	/* Only x86_64 has RIP relative instructions */
	/* Only x86_64 has RIP relative instructions */
+4 −1
Original line number Original line Diff line number Diff line
@@ -65,7 +65,10 @@ unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr)
	 * overwritten by jump destination address. In this case, original
	 * overwritten by jump destination address. In this case, original
	 * bytes must be recovered from op->optinsn.copied_insn buffer.
	 * bytes must be recovered from op->optinsn.copied_insn buffer.
	 */
	 */
	memcpy(buf, (void *)addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
	if (probe_kernel_read(buf, (void *)addr,
		MAX_INSN_SIZE * sizeof(kprobe_opcode_t)))
		return 0UL;

	if (addr == (unsigned long)kp->addr) {
	if (addr == (unsigned long)kp->addr) {
		buf[0] = kp->opcode;
		buf[0] = kp->opcode;
		memcpy(buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE);
		memcpy(buf + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE);