kprobes/x86: Return correct length in __copy_instruction()
PATCH 1/1 kprobes/x86: Return correct length in __copy_instruction()
From: Eugene Shatokhin <[email protected]>
On x86-64, __copy_instruction() always returns 0 (error) if the instruction uses %rip-relative addressing. This is because kernel_insn_init() is called the second time for 'insn' instance in such cases and sets all its fields to 0.
Because of this, trying to place a Kprobe on such instruction will fail, register_kprobe() will return -EINVAL.
This patch fixes the problem.
--- arch/x86/kernel/kprobes/core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
arch/x86/kernel/kprobes/core.c +6 -3
@@ -354,6 +354,7 @@ int __copy_instruction(u8 *dest, u8 *src) {struct insn insn;kprobe_opcode_t buf[MAX_INSN_SIZE ]; +int length;unsigned long recovered_insn =recover_probed_instruction (buf, (unsigned long )src);
@@ -361,16 +362,18 @@ int __copy_instruction(u8 *dest, u8 *src)return 0 ;kernel_insn_init (&insn, (void *)recovered_insn,MAX_INSN_SIZE );insn_get_length (&insn); + length = insn.length; +/* Another subsystem puts a breakpoint, failed to recover */ if (insn.opcode.bytes[0 ] ==BREAKPOINT_INSTRUCTION )return 0 ; -memcpy (dest, insn.kaddr, insn.length); +memcpy (dest, insn.kaddr, length);#ifdef CONFIG_X86_64 if (insn_rip_relative (&insn)) {s64 newdisp;u8 *disp; -kernel_insn_init (&insn, dest, insn.length); +kernel_insn_init (&insn, dest, length);insn_get_displacement (&insn);/* * The copied instruction uses the %rip-relative addressing
@@ -394,7 +397,7 @@ int __copy_instruction(u8 *dest, u8 *src) *(s32 *) disp = (s32) newdisp; }#endif -return insn.length; +return length; }static int arch_copy_kprobe (struct kprobe *p)
tip-bot for Eugene Shatokhin
merge botkprobes/x86: Return correct length in __copy_instruction()
Commit-ID: c80e5c0c23ce2282476fdc64c4b5e3d3a40723fd Gitweb: http://git.kernel.org/tip/c80e5c0c23ce2282476fdc64c4b5e3d3a40723fd Author: Eugene Shatokhin <[email protected]> AuthorDate: Tue, 17 Mar 2015 19:09:18 +0900 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 17 Mar 2015 14:00:38 +0100
kprobes/x86: Return correct length in __copy_instruction()
On x86-64, __copy_instruction() always returns 0 (error) if the instruction uses %rip-relative addressing. This is because kernel_insn_init() is called the second time for 'insn' instance in such cases and sets all its fields to 0.
Because of this, trying to place a kprobe on such instruction will fail, register_kprobe() will return -EINVAL.
This patch fixes the problem.
--- arch/x86/kernel/kprobes/core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
arch/x86/kernel/kprobes/core.c +6 -3
@@ -354,6 +354,7 @@ int __copy_instruction(u8 *dest, u8 *src) {struct insn insn;kprobe_opcode_t buf[MAX_INSN_SIZE ]; +int length;unsigned long recovered_insn =recover_probed_instruction (buf, (unsigned long )src);
@@ -361,16 +362,18 @@ int __copy_instruction(u8 *dest, u8 *src)return 0 ;kernel_insn_init (&insn, (void *)recovered_insn,MAX_INSN_SIZE );insn_get_length (&insn); + length = insn.length; +/* Another subsystem puts a breakpoint, failed to recover */ if (insn.opcode.bytes[0 ] ==BREAKPOINT_INSTRUCTION )return 0 ; -memcpy (dest, insn.kaddr, insn.length); +memcpy (dest, insn.kaddr, length);#ifdef CONFIG_X86_64 if (insn_rip_relative (&insn)) {s64 newdisp;u8 *disp; -kernel_insn_init (&insn, dest, insn.length); +kernel_insn_init (&insn, dest, length);insn_get_displacement (&insn);/* * The copied instruction uses the %rip-relative addressing
@@ -394,7 +397,7 @@ int __copy_instruction(u8 *dest, u8 *src) *(s32 *) disp = (s32) newdisp; }#endif -return insn.length; +return length; }static int arch_copy_kprobe (struct kprobe *p)