Commit 75013fb1 authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Ingo Molnar

kprobes/x86: Fix kernel panic when certain exception-handling addresses are probed

Fix to the exception table entry check by using probed address
instead of the address of copied instruction.

This bug may cause unexpected kernel panic if user probe an address
where an exception can happen which should be fixup by __ex_table
(e.g. copy_from_user.)

Unless user puts a kprobe on such address, this doesn't
cause any problem.

This bug has been introduced years ago, by commit:

  46484688 ("x86/kprobes: Fix a bug which can modify kernel code permanently").
Signed-off-by: default avatarMasami Hiramatsu <mhiramat@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Fixes: 46484688 ("x86/kprobes: Fix a bug which can modify kernel code permanently")
Link: http://lkml.kernel.org/r/148829899399.28855.12581062400757221722.stgit@devboxSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 2d6be4ab
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
#endif #endif
/* Ensure if the instruction can be boostable */ /* Ensure if the instruction can be boostable */
extern int can_boost(kprobe_opcode_t *instruction); extern int can_boost(kprobe_opcode_t *instruction, void *addr);
/* Recover instruction if given address is probed */ /* Recover instruction if given address is probed */
extern unsigned long recover_probed_instruction(kprobe_opcode_t *buf, extern unsigned long recover_probed_instruction(kprobe_opcode_t *buf,
unsigned long addr); unsigned long addr);
......
...@@ -166,12 +166,12 @@ NOKPROBE_SYMBOL(skip_prefixes); ...@@ -166,12 +166,12 @@ NOKPROBE_SYMBOL(skip_prefixes);
* Returns non-zero if opcode is boostable. * Returns non-zero if opcode is boostable.
* RIP relative instructions are adjusted at copying time in 64 bits mode * RIP relative instructions are adjusted at copying time in 64 bits mode
*/ */
int can_boost(kprobe_opcode_t *opcodes) int can_boost(kprobe_opcode_t *opcodes, void *addr)
{ {
kprobe_opcode_t opcode; kprobe_opcode_t opcode;
kprobe_opcode_t *orig_opcodes = opcodes; kprobe_opcode_t *orig_opcodes = opcodes;
if (search_exception_tables((unsigned long)opcodes)) if (search_exception_tables((unsigned long)addr))
return 0; /* Page fault may occur on this address. */ return 0; /* Page fault may occur on this address. */
retry: retry:
...@@ -416,7 +416,7 @@ static int arch_copy_kprobe(struct kprobe *p) ...@@ -416,7 +416,7 @@ static int arch_copy_kprobe(struct kprobe *p)
* __copy_instruction can modify the displacement of the instruction, * __copy_instruction can modify the displacement of the instruction,
* but it doesn't affect boostable check. * but it doesn't affect boostable check.
*/ */
if (can_boost(p->ainsn.insn)) if (can_boost(p->ainsn.insn, p->addr))
p->ainsn.boostable = 0; p->ainsn.boostable = 0;
else else
p->ainsn.boostable = -1; p->ainsn.boostable = -1;
......
...@@ -178,7 +178,7 @@ static int copy_optimized_instructions(u8 *dest, u8 *src) ...@@ -178,7 +178,7 @@ static int copy_optimized_instructions(u8 *dest, u8 *src)
while (len < RELATIVEJUMP_SIZE) { while (len < RELATIVEJUMP_SIZE) {
ret = __copy_instruction(dest + len, src + len); ret = __copy_instruction(dest + len, src + len);
if (!ret || !can_boost(dest + len)) if (!ret || !can_boost(dest + len, src + len))
return -EINVAL; return -EINVAL;
len += ret; len += ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment