x86: jprobe bugfix
authorMasami Hiramatsu <mhiramat@redhat.com>
Tue, 18 Dec 2007 17:05:58 +0000 (18:05 +0100)
committerIngo Molnar <mingo@elte.hu>
Tue, 18 Dec 2007 17:05:58 +0000 (18:05 +0100)
jprobe for x86-64 may cause kernel page fault when the jprobe_return()
is called from incorrect function.

- Use jprobe_saved_regs instead getting it from stack.
  (Especially on x86-64, it may get incorrect data, because
   pt_regs can not be get by using container_of(rsp))
- Change the type of stack pointer to unsigned long *.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
arch/x86/kernel/kprobes_32.c
arch/x86/kernel/kprobes_64.c
include/asm-x86/kprobes_32.h
include/asm-x86/kprobes_64.h

index d87a523..3a020f7 100644 (file)
@@ -727,9 +727,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 
        if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) {
                if (&regs->esp != kcb->jprobe_saved_esp) {
-                       struct pt_regs *saved_regs =
-                           container_of(kcb->jprobe_saved_esp,
-                                           struct pt_regs, esp);
+                       struct pt_regs *saved_regs = &kcb->jprobe_saved_regs;
                        printk("current esp %p does not match saved esp %p\n",
                               &regs->esp, kcb->jprobe_saved_esp);
                        printk("Saved registers for jprobe %p\n", jp);
index 0c46764..a575059 100644 (file)
@@ -716,10 +716,8 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
        struct jprobe *jp = container_of(p, struct jprobe, kp);
 
        if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) {
-               if ((long *)regs->rsp != kcb->jprobe_saved_rsp) {
-                       struct pt_regs *saved_regs =
-                           container_of(kcb->jprobe_saved_rsp,
-                                           struct pt_regs, rsp);
+               if ((unsigned long *)regs->rsp != kcb->jprobe_saved_rsp) {
+                       struct pt_regs *saved_regs = &kcb->jprobe_saved_regs;
                        printk("current rsp %p does not match saved rsp %p\n",
                               (long *)regs->rsp, kcb->jprobe_saved_rsp);
                        printk("Saved registers for jprobe %p\n", jp);
index b772d5b..9fe8f3b 100644 (file)
@@ -73,7 +73,7 @@ struct kprobe_ctlblk {
        unsigned long kprobe_status;
        unsigned long kprobe_old_eflags;
        unsigned long kprobe_saved_eflags;
-       long *jprobe_saved_esp;
+       unsigned long *jprobe_saved_esp;
        struct pt_regs jprobe_saved_regs;
        kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
        struct prev_kprobe prev_kprobe;
index 53f4d85..743d762 100644 (file)
@@ -66,7 +66,7 @@ struct kprobe_ctlblk {
        unsigned long kprobe_status;
        unsigned long kprobe_old_rflags;
        unsigned long kprobe_saved_rflags;
-       long *jprobe_saved_rsp;
+       unsigned long *jprobe_saved_rsp;
        struct pt_regs jprobe_saved_regs;
        kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE];
        struct prev_kprobe prev_kprobe;