Răsfoiți Sursa

[S390] kprobes: Fix the return address of multiple kretprobes

Analog to git commit 737480a0d525dae13306296da08029dff545bc72
fix the return address of subsequent kretprobes when multiple
kretprobes are set on the same function.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Martin Schwidefsky 14 ani în urmă
părinte
comite
89480801a1
1 a modificat fișierele cu 26 adăugiri și 3 ștergeri
  1. 26 3
      arch/s390/kernel/kprobes.c

+ 26 - 3
arch/s390/kernel/kprobes.c

@@ -349,6 +349,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
 	struct hlist_node *node, *tmp;
 	struct hlist_node *node, *tmp;
 	unsigned long flags, orig_ret_address = 0;
 	unsigned long flags, orig_ret_address = 0;
 	unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
 	unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
+	kprobe_opcode_t *correct_ret_addr = NULL;
 
 
 	INIT_HLIST_HEAD(&empty_rp);
 	INIT_HLIST_HEAD(&empty_rp);
 	kretprobe_hash_lock(current, &head, &flags);
 	kretprobe_hash_lock(current, &head, &flags);
@@ -371,10 +372,32 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
 			/* another task is sharing our hash bucket */
 			/* another task is sharing our hash bucket */
 			continue;
 			continue;
 
 
-		if (ri->rp && ri->rp->handler)
-			ri->rp->handler(ri, regs);
+		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;
+	}
+
+	kretprobe_assert(ri, orig_ret_address, trampoline_address);
+
+	correct_ret_addr = ri->ret_addr;
+	hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+		if (ri->task != current)
+			/* another task is sharing our hash bucket */
+			continue;
 
 
 		orig_ret_address = (unsigned long)ri->ret_addr;
 		orig_ret_address = (unsigned long)ri->ret_addr;
+
+		if (ri->rp && ri->rp->handler) {
+			ri->ret_addr = correct_ret_addr;
+			ri->rp->handler(ri, regs);
+		}
+
 		recycle_rp_inst(ri, &empty_rp);
 		recycle_rp_inst(ri, &empty_rp);
 
 
 		if (orig_ret_address != trampoline_address) {
 		if (orig_ret_address != trampoline_address) {
@@ -386,7 +409,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
 			break;
 			break;
 		}
 		}
 	}
 	}
-	kretprobe_assert(ri, orig_ret_address, trampoline_address);
+
 	regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE;
 	regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE;
 
 
 	reset_current_kprobe();
 	reset_current_kprobe();