x86: kretprobe-booster interrupt emulation code fix
authorMasami Hiramatsu <mhiramat@redhat.com>
Mon, 23 Mar 2009 14:14:52 +0000 (10:14 -0400)
committerIngo Molnar <mingo@elte.hu>
Wed, 25 Mar 2009 17:53:29 +0000 (18:53 +0100)
Fix interrupt emulation code in kretprobe-booster according to
pt_regs update (es/ds change and gs adding).

This issue has been reported on systemtap-bugzilla:

  http://sources.redhat.com/bugzilla/show_bug.cgi?id=9965

  | On a -tip kernel on x86_32, kretprobe_example (from samples) triggers the
  | following backtrace when its retprobing a class of functions that cause a
  | copy_from/to_user().
  |
  | BUG: sleeping function called from invalid context at mm/memory.c:3196
  | in_atomic(): 0, irqs_disabled(): 1, pid: 2286, name: cat

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Acked-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Tested-by: Bharata B Rao <bharata@linux.vnet.ibm.com>
Cc: systemtap-ml <systemtap@sources.redhat.com>
LKML-Reference: <49C7995C.2010601@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/kernel/kprobes.c

index 4558dd3918cf3ec66263d7ac8e705acb4a5ea5a9..759095d53a06f9e2913663cfedff5f57dc773818 100644 (file)
@@ -638,13 +638,13 @@ static void __used __kprobes kretprobe_trampoline_holder(void)
 #else
                        "       pushf\n"
                        /*
-                        * Skip cs, ip, orig_ax.
+                        * Skip cs, ip, orig_ax and gs.
                         * trampoline_handler() will plug in these values
                         */
-                       "       subl $12, %esp\n"
+                       "       subl $16, %esp\n"
                        "       pushl %fs\n"
-                       "       pushl %ds\n"
                        "       pushl %es\n"
+                       "       pushl %ds\n"
                        "       pushl %eax\n"
                        "       pushl %ebp\n"
                        "       pushl %edi\n"
@@ -655,10 +655,10 @@ static void __used __kprobes kretprobe_trampoline_holder(void)
                        "       movl %esp, %eax\n"
                        "       call trampoline_handler\n"
                        /* Move flags to cs */
-                       "       movl 52(%esp), %edx\n"
-                       "       movl %edx, 48(%esp)\n"
+                       "       movl 56(%esp), %edx\n"
+                       "       movl %edx, 52(%esp)\n"
                        /* Replace saved flags with true return address. */
-                       "       movl %eax, 52(%esp)\n"
+                       "       movl %eax, 56(%esp)\n"
                        "       popl %ebx\n"
                        "       popl %ecx\n"
                        "       popl %edx\n"
@@ -666,8 +666,8 @@ static void __used __kprobes kretprobe_trampoline_holder(void)
                        "       popl %edi\n"
                        "       popl %ebp\n"
                        "       popl %eax\n"
-                       /* Skip ip, orig_ax, es, ds, fs */
-                       "       addl $20, %esp\n"
+                       /* Skip ds, es, fs, gs, orig_ax and ip */
+                       "       addl $24, %esp\n"
                        "       popf\n"
 #endif
                        "       ret\n");
@@ -691,6 +691,7 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs)
        regs->cs = __KERNEL_CS;
 #else
        regs->cs = __KERNEL_CS | get_kernel_rpl();
+       regs->gs = 0;
 #endif
        regs->ip = trampoline_address;
        regs->orig_ax = ~0UL;