diff options
-rw-r--r-- | arch/arm/probes/kprobes/core.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/arch/arm/probes/kprobes/core.c b/arch/arm/probes/kprobes/core.c index 269f66e66ff5..ad1f4e6a9e33 100644 --- a/arch/arm/probes/kprobes/core.c +++ b/arch/arm/probes/kprobes/core.c | |||
@@ -441,6 +441,7 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) | |||
441 | struct hlist_node *tmp; | 441 | struct hlist_node *tmp; |
442 | unsigned long flags, orig_ret_address = 0; | 442 | unsigned long flags, orig_ret_address = 0; |
443 | unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; | 443 | unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; |
444 | kprobe_opcode_t *correct_ret_addr = NULL; | ||
444 | 445 | ||
445 | INIT_HLIST_HEAD(&empty_rp); | 446 | INIT_HLIST_HEAD(&empty_rp); |
446 | kretprobe_hash_lock(current, &head, &flags); | 447 | kretprobe_hash_lock(current, &head, &flags); |
@@ -463,14 +464,34 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) | |||
463 | /* another task is sharing our hash bucket */ | 464 | /* another task is sharing our hash bucket */ |
464 | continue; | 465 | continue; |
465 | 466 | ||
467 | orig_ret_address = (unsigned long)ri->ret_addr; | ||
468 | |||
469 | if (orig_ret_address != trampoline_address) | ||
470 | /* | ||
471 | * This is the real return address. Any other | ||
472 | * instances associated with this task are for | ||
473 | * other calls deeper on the call stack | ||
474 | */ | ||
475 | break; | ||
476 | } | ||
477 | |||
478 | kretprobe_assert(ri, orig_ret_address, trampoline_address); | ||
479 | |||
480 | correct_ret_addr = ri->ret_addr; | ||
481 | hlist_for_each_entry_safe(ri, tmp, head, hlist) { | ||
482 | if (ri->task != current) | ||
483 | /* another task is sharing our hash bucket */ | ||
484 | continue; | ||
485 | |||
486 | orig_ret_address = (unsigned long)ri->ret_addr; | ||
466 | if (ri->rp && ri->rp->handler) { | 487 | if (ri->rp && ri->rp->handler) { |
467 | __this_cpu_write(current_kprobe, &ri->rp->kp); | 488 | __this_cpu_write(current_kprobe, &ri->rp->kp); |
468 | get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE; | 489 | get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE; |
490 | ri->ret_addr = correct_ret_addr; | ||
469 | ri->rp->handler(ri, regs); | 491 | ri->rp->handler(ri, regs); |
470 | __this_cpu_write(current_kprobe, NULL); | 492 | __this_cpu_write(current_kprobe, NULL); |
471 | } | 493 | } |
472 | 494 | ||
473 | orig_ret_address = (unsigned long)ri->ret_addr; | ||
474 | recycle_rp_inst(ri, &empty_rp); | 495 | recycle_rp_inst(ri, &empty_rp); |
475 | 496 | ||
476 | if (orig_ret_address != trampoline_address) | 497 | if (orig_ret_address != trampoline_address) |
@@ -482,7 +503,6 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) | |||
482 | break; | 503 | break; |
483 | } | 504 | } |
484 | 505 | ||
485 | kretprobe_assert(ri, orig_ret_address, trampoline_address); | ||
486 | kretprobe_hash_unlock(current, &flags); | 506 | kretprobe_hash_unlock(current, &flags); |
487 | 507 | ||
488 | hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) { | 508 | hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) { |