This changes x86/kretprobe stack frame on kretprobe_trampoline
a bit, which now push the kretprobe_trampoline as a fake return
address at the bottom of the stack frame. With this fix, the ORC
unwinder will see the kretprobe_trampoline as a return address.

Signed-off-by: Masami Hiramatsu <mhira...@kernel.org>
Suggested-by: Josh Poimboeuf <jpoim...@redhat.com>
---
 arch/x86/kernel/kprobes/core.c |   31 ++++++++++++++++++++++---------
 1 file changed, 22 insertions(+), 9 deletions(-)

diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index 23255663c434..d7b90541eda1 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -782,28 +782,31 @@ asm(
        ".global kretprobe_trampoline\n"
        ".type kretprobe_trampoline, @function\n"
        "kretprobe_trampoline:\n"
-       /* We don't bother saving the ss register */
 #ifdef CONFIG_X86_64
-       "       pushq %rsp\n"
+       /* Push fake return address to tell the unwinder it's a kretprobe */
+       "       pushq $kretprobe_trampoline\n"
        UNWIND_HINT_FUNC
+       /* Save the sp-8, this will be fixed later */
+       "       pushq %rsp\n"
        "       pushfq\n"
        SAVE_REGS_STRING
        "       movq %rsp, %rdi\n"
        "       call trampoline_handler\n"
-       /* Replace saved sp with true return address. */
-       "       movq %rax, 19*8(%rsp)\n"
        RESTORE_REGS_STRING
+       "       addq $8, %rsp\n"
        "       popfq\n"
 #else
-       "       pushl %esp\n"
+       /* Push fake return address to tell the unwinder it's a kretprobe */
+       "       pushl $kretprobe_trampoline\n"
        UNWIND_HINT_FUNC
+       /* Save the sp-4, this will be fixed later */
+       "       pushl %esp\n"
        "       pushfl\n"
        SAVE_REGS_STRING
        "       movl %esp, %eax\n"
        "       call trampoline_handler\n"
-       /* Replace saved sp with true return address. */
-       "       movl %eax, 15*4(%esp)\n"
        RESTORE_REGS_STRING
+       "       addl $4, %esp\n"
        "       popfl\n"
 #endif
        "       ret\n"
@@ -814,8 +817,10 @@ NOKPROBE_SYMBOL(kretprobe_trampoline);
 /*
  * Called from kretprobe_trampoline
  */
-__used __visible void *trampoline_handler(struct pt_regs *regs)
+__used __visible void trampoline_handler(struct pt_regs *regs)
 {
+       unsigned long *frame_pointer;
+
        /* fixup registers */
        regs->cs = __KERNEL_CS;
 #ifdef CONFIG_X86_32
@@ -823,8 +828,16 @@ __used __visible void *trampoline_handler(struct pt_regs 
*regs)
 #endif
        regs->ip = (unsigned long)&kretprobe_trampoline;
        regs->orig_ax = ~0UL;
+       regs->sp += sizeof(long);
+       frame_pointer = ((unsigned long *)&regs->sp) + 1;
 
-       return (void *)kretprobe_trampoline_handler(regs, &regs->sp);
+       /* Replace fake return address with real one. */
+       *frame_pointer = kretprobe_trampoline_handler(regs, frame_pointer);
+       /*
+        * Move flags to sp so that kretprobe_trapmoline can return
+        * right after popf.
+        */
+       regs->sp = regs->flags;
 }
 NOKPROBE_SYMBOL(trampoline_handler);
 

Reply via email to