aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/kprobes/core.c22
1 files changed, 20 insertions, 2 deletions
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index 18fbe9be2d68..fed46ddb1eef 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -749,11 +749,16 @@ asm(
749NOKPROBE_SYMBOL(kretprobe_trampoline); 749NOKPROBE_SYMBOL(kretprobe_trampoline);
750STACK_FRAME_NON_STANDARD(kretprobe_trampoline); 750STACK_FRAME_NON_STANDARD(kretprobe_trampoline);
751 751
752static struct kprobe kretprobe_kprobe = {
753 .addr = (void *)kretprobe_trampoline,
754};
755
752/* 756/*
753 * Called from kretprobe_trampoline 757 * Called from kretprobe_trampoline
754 */ 758 */
755static __used void *trampoline_handler(struct pt_regs *regs) 759static __used void *trampoline_handler(struct pt_regs *regs)
756{ 760{
761 struct kprobe_ctlblk *kcb;
757 struct kretprobe_instance *ri = NULL; 762 struct kretprobe_instance *ri = NULL;
758 struct hlist_head *head, empty_rp; 763 struct hlist_head *head, empty_rp;
759 struct hlist_node *tmp; 764 struct hlist_node *tmp;
@@ -763,6 +768,17 @@ static __used void *trampoline_handler(struct pt_regs *regs)
763 void *frame_pointer; 768 void *frame_pointer;
764 bool skipped = false; 769 bool skipped = false;
765 770
771 preempt_disable();
772
773 /*
774 * Set a dummy kprobe for avoiding kretprobe recursion.
775 * Since kretprobe never run in kprobe handler, kprobe must not
776 * be running at this point.
777 */
778 kcb = get_kprobe_ctlblk();
779 __this_cpu_write(current_kprobe, &kretprobe_kprobe);
780 kcb->kprobe_status = KPROBE_HIT_ACTIVE;
781
766 INIT_HLIST_HEAD(&empty_rp); 782 INIT_HLIST_HEAD(&empty_rp);
767 kretprobe_hash_lock(current, &head, &flags); 783 kretprobe_hash_lock(current, &head, &flags);
768 /* fixup registers */ 784 /* fixup registers */
@@ -838,10 +854,9 @@ static __used void *trampoline_handler(struct pt_regs *regs)
838 orig_ret_address = (unsigned long)ri->ret_addr; 854 orig_ret_address = (unsigned long)ri->ret_addr;
839 if (ri->rp && ri->rp->handler) { 855 if (ri->rp && ri->rp->handler) {
840 __this_cpu_write(current_kprobe, &ri->rp->kp); 856 __this_cpu_write(current_kprobe, &ri->rp->kp);
841 get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
842 ri->ret_addr = correct_ret_addr; 857 ri->ret_addr = correct_ret_addr;
843 ri->rp->handler(ri, regs); 858 ri->rp->handler(ri, regs);
844 __this_cpu_write(current_kprobe, NULL); 859 __this_cpu_write(current_kprobe, &kretprobe_kprobe);
845 } 860 }
846 861
847 recycle_rp_inst(ri, &empty_rp); 862 recycle_rp_inst(ri, &empty_rp);
@@ -857,6 +872,9 @@ static __used void *trampoline_handler(struct pt_regs *regs)
857 872
858 kretprobe_hash_unlock(current, &flags); 873 kretprobe_hash_unlock(current, &flags);
859 874
875 __this_cpu_write(current_kprobe, NULL);
876 preempt_enable();
877
860 hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) { 878 hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
861 hlist_del(&ri->hlist); 879 hlist_del(&ri->hlist);
862 kfree(ri); 880 kfree(ri);