aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSandeepa Prabhu <sandeepa.s.prabhu@gmail.com>2016-07-08 12:35:53 -0400
committerCatalin Marinas <catalin.marinas@arm.com>2016-07-19 10:03:22 -0400
commitfcfd708b8cf86b8c1ca6ce014d50287f61c0eb88 (patch)
treeaf73c37b2b2fbbce3af32408eed8d8a0b19072b5
parentda6a91252ad98d49b49e83b76c1f032cdf6e5258 (diff)
arm64: Add kernel return probes support (kretprobes)
The pre-handler of this special 'trampoline' kprobe executes the return probe handler functions and restores original return address in ELR_EL1. This way the saved pt_regs still hold the original register context to be carried back to the probed kernel function. Signed-off-by: Sandeepa Prabhu <sandeepa.s.prabhu@gmail.com> Signed-off-by: David A. Long <dave.long@linaro.org> Acked-by: Masami Hiramatsu <mhiramat@kernel.org> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r--arch/arm64/Kconfig1
-rw-r--r--arch/arm64/kernel/probes/kprobes.c90
2 files changed, 90 insertions, 1 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 1f7d644f7f36..6af0e2e5c710 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -89,6 +89,7 @@ config ARM64
89 select HAVE_RCU_TABLE_FREE 89 select HAVE_RCU_TABLE_FREE
90 select HAVE_SYSCALL_TRACEPOINTS 90 select HAVE_SYSCALL_TRACEPOINTS
91 select HAVE_KPROBES 91 select HAVE_KPROBES
92 select HAVE_KRETPROBES if HAVE_KPROBES
92 select IOMMU_DMA if IOMMU_SUPPORT 93 select IOMMU_DMA if IOMMU_SUPPORT
93 select IRQ_DOMAIN 94 select IRQ_DOMAIN
94 select IRQ_FORCED_THREADING 95 select IRQ_FORCED_THREADING
diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c
index be1f074b5736..9c70e8812ea9 100644
--- a/arch/arm64/kernel/probes/kprobes.c
+++ b/arch/arm64/kernel/probes/kprobes.c
@@ -578,7 +578,95 @@ bool arch_within_kprobe_blacklist(unsigned long addr)
578 578
579void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs) 579void __kprobes __used *trampoline_probe_handler(struct pt_regs *regs)
580{ 580{
581 return NULL; 581 struct kretprobe_instance *ri = NULL;
582 struct hlist_head *head, empty_rp;
583 struct hlist_node *tmp;
584 unsigned long flags, orig_ret_address = 0;
585 unsigned long trampoline_address =
586 (unsigned long)&kretprobe_trampoline;
587 kprobe_opcode_t *correct_ret_addr = NULL;
588
589 INIT_HLIST_HEAD(&empty_rp);
590 kretprobe_hash_lock(current, &head, &flags);
591
592 /*
593 * It is possible to have multiple instances associated with a given
594 * task either because multiple functions in the call path have
595 * return probes installed on them, and/or more than one
596 * return probe was registered for a target function.
597 *
598 * We can handle this because:
599 * - instances are always pushed into the head of the list
600 * - when multiple return probes are registered for the same
601 * function, the (chronologically) first instance's ret_addr
602 * will be the real return address, and all the rest will
603 * point to kretprobe_trampoline.
604 */
605 hlist_for_each_entry_safe(ri, tmp, head, hlist) {
606 if (ri->task != current)
607 /* another task is sharing our hash bucket */
608 continue;
609
610 orig_ret_address = (unsigned long)ri->ret_addr;
611
612 if (orig_ret_address != trampoline_address)
613 /*
614 * This is the real return address. Any other
615 * instances associated with this task are for
616 * other calls deeper on the call stack
617 */
618 break;
619 }
620
621 kretprobe_assert(ri, orig_ret_address, trampoline_address);
622
623 correct_ret_addr = ri->ret_addr;
624 hlist_for_each_entry_safe(ri, tmp, head, hlist) {
625 if (ri->task != current)
626 /* another task is sharing our hash bucket */
627 continue;
628
629 orig_ret_address = (unsigned long)ri->ret_addr;
630 if (ri->rp && ri->rp->handler) {
631 __this_cpu_write(current_kprobe, &ri->rp->kp);
632 get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
633 ri->ret_addr = correct_ret_addr;
634 ri->rp->handler(ri, regs);
635 __this_cpu_write(current_kprobe, NULL);
636 }
637
638 recycle_rp_inst(ri, &empty_rp);
639
640 if (orig_ret_address != trampoline_address)
641 /*
642 * This is the real return address. Any other
643 * instances associated with this task are for
644 * other calls deeper on the call stack
645 */
646 break;
647 }
648
649 kretprobe_hash_unlock(current, &flags);
650
651 hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) {
652 hlist_del(&ri->hlist);
653 kfree(ri);
654 }
655 return (void *)orig_ret_address;
656}
657
658void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
659 struct pt_regs *regs)
660{
661 ri->ret_addr = (kprobe_opcode_t *)regs->regs[30];
662
663 /* replace return addr (x30) with trampoline */
664 regs->regs[30] = (long)&kretprobe_trampoline;
665}
666
667int __kprobes arch_trampoline_kprobe(struct kprobe *p)
668{
669 return 0;
582} 670}
583 671
584int __init arch_init_kprobes(void) 672int __init arch_init_kprobes(void)