diff options
| -rw-r--r-- | arch/x86/kernel/kprobes.c | 25 |
1 files changed, 22 insertions, 3 deletions
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index 1bfb6cf4dd55..770ebfb349e9 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c | |||
| @@ -709,6 +709,7 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) | |||
| 709 | struct hlist_node *node, *tmp; | 709 | struct hlist_node *node, *tmp; |
| 710 | unsigned long flags, orig_ret_address = 0; | 710 | unsigned long flags, orig_ret_address = 0; |
| 711 | unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; | 711 | unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; |
| 712 | kprobe_opcode_t *correct_ret_addr = NULL; | ||
| 712 | 713 | ||
| 713 | INIT_HLIST_HEAD(&empty_rp); | 714 | INIT_HLIST_HEAD(&empty_rp); |
| 714 | kretprobe_hash_lock(current, &head, &flags); | 715 | kretprobe_hash_lock(current, &head, &flags); |
| @@ -740,14 +741,34 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) | |||
| 740 | /* another task is sharing our hash bucket */ | 741 | /* another task is sharing our hash bucket */ |
| 741 | continue; | 742 | continue; |
| 742 | 743 | ||
| 744 | orig_ret_address = (unsigned long)ri->ret_addr; | ||
| 745 | |||
| 746 | if (orig_ret_address != trampoline_address) | ||
| 747 | /* | ||
| 748 | * This is the real return address. Any other | ||
| 749 | * instances associated with this task are for | ||
| 750 | * other calls deeper on the call stack | ||
| 751 | */ | ||
| 752 | break; | ||
| 753 | } | ||
| 754 | |||
| 755 | kretprobe_assert(ri, orig_ret_address, trampoline_address); | ||
| 756 | |||
| 757 | correct_ret_addr = ri->ret_addr; | ||
| 758 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { | ||
| 759 | if (ri->task != current) | ||
| 760 | /* another task is sharing our hash bucket */ | ||
| 761 | continue; | ||
| 762 | |||
| 763 | orig_ret_address = (unsigned long)ri->ret_addr; | ||
| 743 | if (ri->rp && ri->rp->handler) { | 764 | if (ri->rp && ri->rp->handler) { |
| 744 | __get_cpu_var(current_kprobe) = &ri->rp->kp; | 765 | __get_cpu_var(current_kprobe) = &ri->rp->kp; |
| 745 | get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE; | 766 | get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE; |
| 767 | ri->ret_addr = correct_ret_addr; | ||
| 746 | ri->rp->handler(ri, regs); | 768 | ri->rp->handler(ri, regs); |
| 747 | __get_cpu_var(current_kprobe) = NULL; | 769 | __get_cpu_var(current_kprobe) = NULL; |
| 748 | } | 770 | } |
| 749 | 771 | ||
| 750 | orig_ret_address = (unsigned long)ri->ret_addr; | ||
| 751 | recycle_rp_inst(ri, &empty_rp); | 772 | recycle_rp_inst(ri, &empty_rp); |
| 752 | 773 | ||
| 753 | if (orig_ret_address != trampoline_address) | 774 | if (orig_ret_address != trampoline_address) |
| @@ -759,8 +780,6 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) | |||
| 759 | break; | 780 | break; |
| 760 | } | 781 | } |
| 761 | 782 | ||
| 762 | kretprobe_assert(ri, orig_ret_address, trampoline_address); | ||
| 763 | |||
| 764 | kretprobe_hash_unlock(current, &flags); | 783 | kretprobe_hash_unlock(current, &flags); |
| 765 | 784 | ||
| 766 | hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { | 785 | hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { |
