Revert "ia64: kprobes: Use generic kretprobe trampoline handler"
authorMasami Hiramatsu <mhiramat@kernel.org>
Tue, 26 Apr 2022 14:26:14 +0000 (23:26 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 1 May 2022 15:00:37 +0000 (17:00 +0200)
This reverts commit d3380de483d55d904fb94a241406b34ed2fada7d.

Since this commit is a part of generic kretprobe trampoline
handler series, without the other patches in that series, this
causes a build error on ia64.

Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/ia64/kernel/kprobes.c

index 8207b897b49dd5197dcb56d8da41253e0b8d9e66..aa41bd5cf9b771ecda27e50a8acf7c3f0cf500fb 100644 (file)
@@ -409,9 +409,83 @@ static void kretprobe_trampoline(void)
 {
 }
 
+/*
+ * At this point the target function has been tricked into
+ * returning into our trampoline.  Lookup the associated instance
+ * and then:
+ *    - call the handler function
+ *    - cleanup by marking the instance as unused
+ *    - long jump back to the original return address
+ */
 int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 {
-       regs->cr_iip = __kretprobe_trampoline_handler(regs, kretprobe_trampoline, NULL);
+       struct kretprobe_instance *ri = NULL;
+       struct hlist_head *head, empty_rp;
+       struct hlist_node *tmp;
+       unsigned long flags, orig_ret_address = 0;
+       unsigned long trampoline_address =
+               ((struct fnptr *)kretprobe_trampoline)->ip;
+
+       INIT_HLIST_HEAD(&empty_rp);
+       kretprobe_hash_lock(current, &head, &flags);
+
+       /*
+        * It is possible to have multiple instances associated with a given
+        * task either because an multiple functions in the call path
+        * have a return probe installed on them, and/or more than one return
+        * return probe was registered for a target function.
+        *
+        * We can handle this because:
+        *     - instances are always inserted at the head of the list
+        *     - when multiple return probes are registered for the same
+        *       function, the first instance's ret_addr will point to the
+        *       real return address, and all the rest will point to
+        *       kretprobe_trampoline
+        */
+       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
+               if (ri->task != current)
+                       /* another task is sharing our hash bucket */
+                       continue;
+
+               orig_ret_address = (unsigned long)ri->ret_addr;
+               if (orig_ret_address != trampoline_address)
+                       /*
+                        * This is the real return address. Any other
+                        * instances associated with this task are for
+                        * other calls deeper on the call stack
+                        */
+                       break;
+       }
+
+       regs->cr_iip = orig_ret_address;
+
+       hlist_for_each_entry_safe(ri, tmp, head, hlist) {
+               if (ri->task != current)
+                       /* another task is sharing our hash bucket */
+                       continue;
+
+               if (ri->rp && ri->rp->handler)
+                       ri->rp->handler(ri, regs);
+
+               orig_ret_address = (unsigned long)ri->ret_addr;
+               recycle_rp_inst(ri, &empty_rp);
+
+               if (orig_ret_address != trampoline_address)
+                       /*
+                        * This is the real return address. Any other
+                        * instances associated with this task are for
+                        * other calls deeper on the call stack
+                        */
+                       break;
+       }
+       kretprobe_assert(ri, orig_ret_address, trampoline_address);
+
+       kretprobe_hash_unlock(current, &flags);
+
+       hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
+               hlist_del(&ri->hlist);
+               kfree(ri);
+       }
        /*
         * By returning a non-zero value, we are telling
         * kprobe_handler() that we don't want the post_handler
@@ -424,7 +498,6 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
                                      struct pt_regs *regs)
 {
        ri->ret_addr = (kprobe_opcode_t *)regs->b0;
-       ri->fp = NULL;
 
        /* Replace the return addr with trampoline addr */
        regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip;