x86/kprobes: Verify stack frame on kretprobe

Verify the stack frame pointer on kretprobe trampoline handler,
If the stack frame pointer does not match, it skips the wrong
entry and tries to find correct one.

This can happen if user puts the kretprobe on the function
which can be used in the path of ftrace user-function call.
Such functions should not be probed, so this adds a warning
message that reports which function should be blacklisted.

Tested-by: Andrea Righi <righi.andrea@gmail.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/155094059185.6137.15527904013362842072.stgit@devbox
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by Masami Hiramatsu and committed by Ingo Molnar 3ff9c075 3fe3331b

+27
+26
arch/x86/kernel/kprobes/core.c
··· 569 unsigned long *sara = stack_addr(regs); 570 571 ri->ret_addr = (kprobe_opcode_t *) *sara; 572 573 /* Replace the return addr with trampoline addr */ 574 *sara = (unsigned long) &kretprobe_trampoline; ··· 760 unsigned long flags, orig_ret_address = 0; 761 unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; 762 kprobe_opcode_t *correct_ret_addr = NULL; 763 764 INIT_HLIST_HEAD(&empty_rp); 765 kretprobe_hash_lock(current, &head, &flags); 766 /* fixup registers */ 767 #ifdef CONFIG_X86_64 768 regs->cs = __KERNEL_CS; 769 #else 770 regs->cs = __KERNEL_CS | get_kernel_rpl(); 771 regs->gs = 0; 772 #endif 773 regs->ip = trampoline_address; 774 regs->orig_ax = ~0UL; ··· 796 if (ri->task != current) 797 /* another task is sharing our hash bucket */ 798 continue; 799 800 orig_ret_address = (unsigned long)ri->ret_addr; 801 802 if (orig_ret_address != trampoline_address) 803 /* ··· 831 hlist_for_each_entry_safe(ri, tmp, head, hlist) { 832 if (ri->task != current) 833 /* another task is sharing our hash bucket */ 834 continue; 835 836 orig_ret_address = (unsigned long)ri->ret_addr;
··· 569 unsigned long *sara = stack_addr(regs); 570 571 ri->ret_addr = (kprobe_opcode_t *) *sara; 572 + ri->fp = sara; 573 574 /* Replace the return addr with trampoline addr */ 575 *sara = (unsigned long) &kretprobe_trampoline; ··· 759 unsigned long flags, orig_ret_address = 0; 760 unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; 761 kprobe_opcode_t *correct_ret_addr = NULL; 762 + void *frame_pointer; 763 + bool skipped = false; 764 765 INIT_HLIST_HEAD(&empty_rp); 766 kretprobe_hash_lock(current, &head, &flags); 767 /* fixup registers */ 768 #ifdef CONFIG_X86_64 769 regs->cs = __KERNEL_CS; 770 + /* On x86-64, we use pt_regs->sp for return address holder. */ 771 + frame_pointer = &regs->sp; 772 #else 773 regs->cs = __KERNEL_CS | get_kernel_rpl(); 774 regs->gs = 0; 775 + /* On x86-32, we use pt_regs->flags for return address holder. */ 776 + frame_pointer = &regs->flags; 777 #endif 778 regs->ip = trampoline_address; 779 regs->orig_ax = ~0UL; ··· 789 if (ri->task != current) 790 /* another task is sharing our hash bucket */ 791 continue; 792 + /* 793 + * Return probes must be pushed on this hash list correct 794 + * order (same as return order) so that it can be poped 795 + * correctly. However, if we find it is pushed it incorrect 796 + * order, this means we find a function which should not be 797 + * probed, because the wrong order entry is pushed on the 798 + * path of processing other kretprobe itself. 799 + */ 800 + if (ri->fp != frame_pointer) { 801 + if (!skipped) 802 + pr_warn("kretprobe is stacked incorrectly. Trying to fixup.\n"); 803 + skipped = true; 804 + continue; 805 + } 806 807 orig_ret_address = (unsigned long)ri->ret_addr; 808 + if (skipped) 809 + pr_warn("%ps must be blacklisted because of incorrect kretprobe order\n", 810 + ri->rp->kp.addr); 811 812 if (orig_ret_address != trampoline_address) 813 /* ··· 807 hlist_for_each_entry_safe(ri, tmp, head, hlist) { 808 if (ri->task != current) 809 /* another task is sharing our hash bucket */ 810 + continue; 811 + if (ri->fp != frame_pointer) 812 continue; 813 814 orig_ret_address = (unsigned long)ri->ret_addr;
+1
include/linux/kprobes.h
··· 173 struct kretprobe *rp; 174 kprobe_opcode_t *ret_addr; 175 struct task_struct *task; 176 char data[0]; 177 }; 178
··· 173 struct kretprobe *rp; 174 kprobe_opcode_t *ret_addr; 175 struct task_struct *task; 176 + void *fp; 177 char data[0]; 178 }; 179