This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
[PATCH] kprobes: bad manupilation of 2 byte opcode on x86_64
- From: Satoshi Oshima <soshima at redhat dot com>
- To: Andi Kleen <ak at suse dot de>, Andrew Morton <akpm at osdl dot org>
- Cc: linux-kernel at vger dot kernel dot org, systemtap at sources dot redhat dot com, "Keshavamurthy, Anil S" <anil dot s dot keshavamurthy at intel dot com>, Ananth N Mavinakayanahalli <mananth at in dot ibm dot com>, Jim Keniston <jkenisto at us dot ibm dot com>, Prasanna S Panchamukhi <prasanna at in dot ibm dot com>, "Hideo AOKI at redhat" <haoki at redhat dot com>, Masami Hiramatsu <hiramatu at sdl dot hitachi dot co dot jp>, sugita <sugita at sdl dot hitachi dot co dot jp>
- Date: Thu, 18 May 2006 17:32:18 -0400
- Subject: [PATCH] kprobes: bad manupilation of 2 byte opcode on x86_64
Hi Andi and Andrew,
I found a bug of kprobes on x86_64.
I attached the fix of this bug.
Problem:
If we put a probe onto a callq instruction and the probe
is executed, kernel panic of Bad RIP value occurs.
Root cause:
If resume_execution() found 0xff at first byte of
p->ainsn.insn, it must check the _second_ byte.
But current resume_execution check _first_ byte again.
I changed it checks second byte of p->ainsn.insn.
Kprobes on i386 don't have this problem, because
the implementation is a little bit different from
x86_64.
Regards,
Satoshi Oshima
Hitachi Computer Product (America) Inc.
----------------------------------------------
diff -Narup linux-2.6.17-rc3-mm1.orig/arch/x86_64/kernel/kprobes.c x86_64_bugifx/arch/x86_64/kernel/kprobes.c
--- linux-2.6.17-rc3-mm1.orig/arch/x86_64/kernel/kprobes.c 2006-05-04 12:34:44.000000000 -0400
+++ x86_64_bugifx/arch/x86_64/kernel/kprobes.c 2006-05-12 16:02:35.000000000 -0400
@@ -514,13 +514,13 @@ static void __kprobes resume_execution(s
*tos = orig_rip + (*tos - copy_rip);
break;
case 0xff:
- if ((*insn & 0x30) == 0x10) {
+ if ((insn[1] & 0x30) == 0x10) {
/* call absolute, indirect */
/* Fix return addr; rip is correct. */
next_rip = regs->rip;
*tos = orig_rip + (*tos - copy_rip);
- } else if (((*insn & 0x31) == 0x20) || /* jmp near, absolute indirect */
- ((*insn & 0x31) == 0x21)) { /* jmp far, absolute indirect */
+ } else if (((insn[1] & 0x31) == 0x20) || /* jmp near, absolute indirect */
+ ((insn[1] & 0x31) == 0x21)) { /* jmp far, absolute indirect */
/* rip is correct. */
next_rip = regs->rip;
}