diff --git a/kernel.spec b/kernel.spec index 4dbe47ee5..768af16bf 100644 --- a/kernel.spec +++ b/kernel.spec @@ -710,6 +710,8 @@ Patch12050: direct-io-move-aio_complete-into-end_io.patch Patch12060: ext4-move-aio-completion-after-unwritten-extent-conversion.patch Patch12070: xfs-move-aio-completion-after-unwritten-extent-conversion.patch +Patch12080: kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1305,6 +1307,9 @@ ApplyPatch direct-io-move-aio_complete-into-end_io.patch ApplyPatch ext4-move-aio-completion-after-unwritten-extent-conversion.patch ApplyPatch xfs-move-aio-completion-after-unwritten-extent-conversion.patch +# bz 610941 +ApplyPatch kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch + # END OF PATCH APPLICATIONS %endif @@ -1893,6 +1898,7 @@ fi %changelog * Fri Aug 27 2010 Chuck Ebbert 2.6.35.4-12 - Linux 2.6.35.4 +- kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch (#610941) * Wed Aug 25 2010 Chuck Ebbert 2.6.35.4-11.rc1 - Linux 2.6.35.4-rc1 diff --git a/kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch b/kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch new file mode 100644 index 000000000..ae70d4126 --- /dev/null +++ b/kprobes-x86-fix-kprobes-to-skip-prefixes-correctly.patch @@ -0,0 +1,98 @@ +From: Masami Hiramatsu +Date: Tue, 29 Jun 2010 05:53:50 +0000 (+0900) +Subject: kprobes/x86: Fix kprobes to skip prefixes correctly +X-Git-Tag: v2.6.36-rc1~41^2~53 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=567a9fd86735ccdc897768ed2dacdd5e83a13509 + +kprobes/x86: Fix kprobes to skip prefixes correctly + +Fix resume_execution() and is_IF_modifier() to skip x86 +instruction prefixes correctly by using x86 instruction +attribute. + +Without this fix, resume_execution() can't handle instructions +which have non-REX prefixes (REX prefixes are skipped). This +will cause unexpected kernel panic by hitting bad address when a +kprobe hits on two-byte ret (e.g. "repz ret" generated for +Athlon/K8 optimization), because it just checks "repz" and can't +recognize the "ret" instruction. + +These prefixes can be found easily with x86 instruction +attribute. This patch introduces skip_prefixes() and uses it in +resume_execution() and is_IF_modifier() to skip prefixes. + +Signed-off-by: Masami Hiramatsu +Cc: Ananth N Mavinakayanahalli +LKML-Reference: <4C298A6E.8070609@hitachi.com> +Signed-off-by: Ingo Molnar +--- + +diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c +index 345a4b1..175f85c 100644 +--- a/arch/x86/kernel/kprobes.c ++++ b/arch/x86/kernel/kprobes.c +@@ -126,16 +126,22 @@ static void __kprobes synthesize_reljump(void *from, void *to) + } + + /* +- * Check for the REX prefix which can only exist on X86_64 +- * X86_32 always returns 0 ++ * Skip the prefixes of the instruction. + */ +-static int __kprobes is_REX_prefix(kprobe_opcode_t *insn) ++static kprobe_opcode_t *__kprobes skip_prefixes(kprobe_opcode_t *insn) + { ++ insn_attr_t attr; ++ ++ attr = inat_get_opcode_attribute((insn_byte_t)*insn); ++ while (inat_is_legacy_prefix(attr)) { ++ insn++; ++ attr = inat_get_opcode_attribute((insn_byte_t)*insn); ++ } + #ifdef CONFIG_X86_64 +- if ((*insn & 0xf0) == 0x40) +- return 1; ++ if (inat_is_rex_prefix(attr)) ++ insn++; + #endif +- return 0; ++ return insn; + } + + /* +@@ -272,6 +278,9 @@ static int __kprobes can_probe(unsigned long paddr) + */ + static int __kprobes is_IF_modifier(kprobe_opcode_t *insn) + { ++ /* Skip prefixes */ ++ insn = skip_prefixes(insn); ++ + switch (*insn) { + case 0xfa: /* cli */ + case 0xfb: /* sti */ +@@ -280,13 +289,6 @@ static int __kprobes is_IF_modifier(kprobe_opcode_t *insn) + return 1; + } + +- /* +- * on X86_64, 0x40-0x4f are REX prefixes so we need to look +- * at the next byte instead.. but of course not recurse infinitely +- */ +- if (is_REX_prefix(insn)) +- return is_IF_modifier(++insn); +- + return 0; + } + +@@ -803,9 +805,8 @@ static void __kprobes resume_execution(struct kprobe *p, + unsigned long orig_ip = (unsigned long)p->addr; + kprobe_opcode_t *insn = p->ainsn.insn; + +- /*skip the REX prefix*/ +- if (is_REX_prefix(insn)) +- insn++; ++ /* Skip prefixes */ ++ insn = skip_prefixes(insn); + + regs->flags &= ~X86_EFLAGS_TF; + switch (*insn) {