Chuck Ebbert 8f132e3
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Chuck Ebbert 8f132e3
Date: Tue, 29 Jun 2010 05:53:50 +0000 (+0900)
Chuck Ebbert 8f132e3
Subject: kprobes/x86: Fix kprobes to skip prefixes correctly
Chuck Ebbert 8f132e3
X-Git-Tag: v2.6.36-rc1~41^2~53
Chuck Ebbert 8f132e3
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=567a9fd86735ccdc897768ed2dacdd5e83a13509
Chuck Ebbert 8f132e3
Chuck Ebbert 8f132e3
kprobes/x86: Fix kprobes to skip prefixes correctly
Chuck Ebbert 8f132e3
Chuck Ebbert 8f132e3
Fix resume_execution() and is_IF_modifier() to skip x86
Chuck Ebbert 8f132e3
instruction prefixes correctly by using x86 instruction
Chuck Ebbert 8f132e3
attribute.
Chuck Ebbert 8f132e3
Chuck Ebbert 8f132e3
Without this fix, resume_execution() can't handle instructions
Chuck Ebbert 8f132e3
which have non-REX prefixes (REX prefixes are skipped). This
Chuck Ebbert 8f132e3
will cause unexpected kernel panic by hitting bad address when a
Chuck Ebbert 8f132e3
kprobe hits on two-byte ret (e.g. "repz ret" generated for
Chuck Ebbert 8f132e3
Athlon/K8 optimization), because it just checks "repz" and can't
Chuck Ebbert 8f132e3
recognize the "ret" instruction.
Chuck Ebbert 8f132e3
Chuck Ebbert 8f132e3
These prefixes can be found easily with x86 instruction
Chuck Ebbert 8f132e3
attribute. This patch introduces skip_prefixes() and uses it in
Chuck Ebbert 8f132e3
resume_execution() and is_IF_modifier() to skip prefixes.
Chuck Ebbert 8f132e3
Chuck Ebbert 8f132e3
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Chuck Ebbert 8f132e3
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Chuck Ebbert 8f132e3
LKML-Reference: <4C298A6E.8070609@hitachi.com>
Chuck Ebbert 8f132e3
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Chuck Ebbert 8f132e3
---
Chuck Ebbert 8f132e3
Chuck Ebbert 8f132e3
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
Chuck Ebbert 8f132e3
index 345a4b1..175f85c 100644
Chuck Ebbert 8f132e3
--- a/arch/x86/kernel/kprobes.c
Chuck Ebbert 8f132e3
+++ b/arch/x86/kernel/kprobes.c
Chuck Ebbert 8f132e3
@@ -126,16 +126,22 @@ static void __kprobes synthesize_reljump(void *from, void *to)
Chuck Ebbert 8f132e3
 }
Chuck Ebbert 8f132e3
 
Chuck Ebbert 8f132e3
 /*
Chuck Ebbert 8f132e3
- * Check for the REX prefix which can only exist on X86_64
Chuck Ebbert 8f132e3
- * X86_32 always returns 0
Chuck Ebbert 8f132e3
+ * Skip the prefixes of the instruction.
Chuck Ebbert 8f132e3
  */
Chuck Ebbert 8f132e3
-static int __kprobes is_REX_prefix(kprobe_opcode_t *insn)
Chuck Ebbert 8f132e3
+static kprobe_opcode_t *__kprobes skip_prefixes(kprobe_opcode_t *insn)
Chuck Ebbert 8f132e3
 {
Chuck Ebbert 8f132e3
+	insn_attr_t attr;
Chuck Ebbert 8f132e3
+
Chuck Ebbert 8f132e3
+	attr = inat_get_opcode_attribute((insn_byte_t)*insn);
Chuck Ebbert 8f132e3
+	while (inat_is_legacy_prefix(attr)) {
Chuck Ebbert 8f132e3
+		insn++;
Chuck Ebbert 8f132e3
+		attr = inat_get_opcode_attribute((insn_byte_t)*insn);
Chuck Ebbert 8f132e3
+	}
Chuck Ebbert 8f132e3
 #ifdef CONFIG_X86_64
Chuck Ebbert 8f132e3
-	if ((*insn & 0xf0) == 0x40)
Chuck Ebbert 8f132e3
-		return 1;
Chuck Ebbert 8f132e3
+	if (inat_is_rex_prefix(attr))
Chuck Ebbert 8f132e3
+		insn++;
Chuck Ebbert 8f132e3
 #endif
Chuck Ebbert 8f132e3
-	return 0;
Chuck Ebbert 8f132e3
+	return insn;
Chuck Ebbert 8f132e3
 }
Chuck Ebbert 8f132e3
 
Chuck Ebbert 8f132e3
 /*
Chuck Ebbert 8f132e3
@@ -272,6 +278,9 @@ static int __kprobes can_probe(unsigned long paddr)
Chuck Ebbert 8f132e3
  */
Chuck Ebbert 8f132e3
 static int __kprobes is_IF_modifier(kprobe_opcode_t *insn)
Chuck Ebbert 8f132e3
 {
Chuck Ebbert 8f132e3
+	/* Skip prefixes */
Chuck Ebbert 8f132e3
+	insn = skip_prefixes(insn);
Chuck Ebbert 8f132e3
+
Chuck Ebbert 8f132e3
 	switch (*insn) {
Chuck Ebbert 8f132e3
 	case 0xfa:		/* cli */
Chuck Ebbert 8f132e3
 	case 0xfb:		/* sti */
Chuck Ebbert 8f132e3
@@ -280,13 +289,6 @@ static int __kprobes is_IF_modifier(kprobe_opcode_t *insn)
Chuck Ebbert 8f132e3
 		return 1;
Chuck Ebbert 8f132e3
 	}
Chuck Ebbert 8f132e3
 
Chuck Ebbert 8f132e3
-	/*
Chuck Ebbert 8f132e3
-	 * on X86_64, 0x40-0x4f are REX prefixes so we need to look
Chuck Ebbert 8f132e3
-	 * at the next byte instead.. but of course not recurse infinitely
Chuck Ebbert 8f132e3
-	 */
Chuck Ebbert 8f132e3
-	if (is_REX_prefix(insn))
Chuck Ebbert 8f132e3
-		return is_IF_modifier(++insn);
Chuck Ebbert 8f132e3
-
Chuck Ebbert 8f132e3
 	return 0;
Chuck Ebbert 8f132e3
 }
Chuck Ebbert 8f132e3
 
Chuck Ebbert 8f132e3
@@ -803,9 +805,8 @@ static void __kprobes resume_execution(struct kprobe *p,
Chuck Ebbert 8f132e3
 	unsigned long orig_ip = (unsigned long)p->addr;
Chuck Ebbert 8f132e3
 	kprobe_opcode_t *insn = p->ainsn.insn;
Chuck Ebbert 8f132e3
 
Chuck Ebbert 8f132e3
-	/*skip the REX prefix*/
Chuck Ebbert 8f132e3
-	if (is_REX_prefix(insn))
Chuck Ebbert 8f132e3
-		insn++;
Chuck Ebbert 8f132e3
+	/* Skip prefixes */
Chuck Ebbert 8f132e3
+	insn = skip_prefixes(insn);
Chuck Ebbert 8f132e3
 
Chuck Ebbert 8f132e3
 	regs->flags &= ~X86_EFLAGS_TF;
Chuck Ebbert 8f132e3
 	switch (*insn) {