aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/uprobes.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/uprobes.c')
-rw-r--r--arch/x86/kernel/uprobes.c107
1 files changed, 103 insertions, 4 deletions
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index a3755d293a48..85c7ef23d99f 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -528,11 +528,11 @@ static int default_pre_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
528 return 0; 528 return 0;
529} 529}
530 530
531static int push_ret_address(struct pt_regs *regs, unsigned long ip) 531static int emulate_push_stack(struct pt_regs *regs, unsigned long val)
532{ 532{
533 unsigned long new_sp = regs->sp - sizeof_long(); 533 unsigned long new_sp = regs->sp - sizeof_long();
534 534
535 if (copy_to_user((void __user *)new_sp, &ip, sizeof_long())) 535 if (copy_to_user((void __user *)new_sp, &val, sizeof_long()))
536 return -EFAULT; 536 return -EFAULT;
537 537
538 regs->sp = new_sp; 538 regs->sp = new_sp;
@@ -566,7 +566,7 @@ static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs
566 regs->ip += correction; 566 regs->ip += correction;
567 } else if (auprobe->defparam.fixups & UPROBE_FIX_CALL) { 567 } else if (auprobe->defparam.fixups & UPROBE_FIX_CALL) {
568 regs->sp += sizeof_long(); /* Pop incorrect return address */ 568 regs->sp += sizeof_long(); /* Pop incorrect return address */
569 if (push_ret_address(regs, utask->vaddr + auprobe->defparam.ilen)) 569 if (emulate_push_stack(regs, utask->vaddr + auprobe->defparam.ilen))
570 return -ERESTART; 570 return -ERESTART;
571 } 571 }
572 /* popf; tell the caller to not touch TF */ 572 /* popf; tell the caller to not touch TF */
@@ -655,7 +655,7 @@ static bool branch_emulate_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
655 * 655 *
656 * But there is corner case, see the comment in ->post_xol(). 656 * But there is corner case, see the comment in ->post_xol().
657 */ 657 */
658 if (push_ret_address(regs, new_ip)) 658 if (emulate_push_stack(regs, new_ip))
659 return false; 659 return false;
660 } else if (!check_jmp_cond(auprobe, regs)) { 660 } else if (!check_jmp_cond(auprobe, regs)) {
661 offs = 0; 661 offs = 0;
@@ -665,6 +665,16 @@ static bool branch_emulate_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
665 return true; 665 return true;
666} 666}
667 667
668static bool push_emulate_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
669{
670 unsigned long *src_ptr = (void *)regs + auprobe->push.reg_offset;
671
672 if (emulate_push_stack(regs, *src_ptr))
673 return false;
674 regs->ip += auprobe->push.ilen;
675 return true;
676}
677
668static int branch_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs) 678static int branch_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
669{ 679{
670 BUG_ON(!branch_is_call(auprobe)); 680 BUG_ON(!branch_is_call(auprobe));
@@ -703,6 +713,10 @@ static const struct uprobe_xol_ops branch_xol_ops = {
703 .post_xol = branch_post_xol_op, 713 .post_xol = branch_post_xol_op,
704}; 714};
705 715
716static const struct uprobe_xol_ops push_xol_ops = {
717 .emulate = push_emulate_op,
718};
719
706/* Returns -ENOSYS if branch_xol_ops doesn't handle this insn */ 720/* Returns -ENOSYS if branch_xol_ops doesn't handle this insn */
707static int branch_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn) 721static int branch_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn)
708{ 722{
@@ -750,6 +764,87 @@ static int branch_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn)
750 return 0; 764 return 0;
751} 765}
752 766
767/* Returns -ENOSYS if push_xol_ops doesn't handle this insn */
768static int push_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn)
769{
770 u8 opc1 = OPCODE1(insn), reg_offset = 0;
771
772 if (opc1 < 0x50 || opc1 > 0x57)
773 return -ENOSYS;
774
775 if (insn->length > 2)
776 return -ENOSYS;
777 if (insn->length == 2) {
778 /* only support rex_prefix 0x41 (x64 only) */
779#ifdef CONFIG_X86_64
780 if (insn->rex_prefix.nbytes != 1 ||
781 insn->rex_prefix.bytes[0] != 0x41)
782 return -ENOSYS;
783
784 switch (opc1) {
785 case 0x50:
786 reg_offset = offsetof(struct pt_regs, r8);
787 break;
788 case 0x51:
789 reg_offset = offsetof(struct pt_regs, r9);
790 break;
791 case 0x52:
792 reg_offset = offsetof(struct pt_regs, r10);
793 break;
794 case 0x53:
795 reg_offset = offsetof(struct pt_regs, r11);
796 break;
797 case 0x54:
798 reg_offset = offsetof(struct pt_regs, r12);
799 break;
800 case 0x55:
801 reg_offset = offsetof(struct pt_regs, r13);
802 break;
803 case 0x56:
804 reg_offset = offsetof(struct pt_regs, r14);
805 break;
806 case 0x57:
807 reg_offset = offsetof(struct pt_regs, r15);
808 break;
809 }
810#else
811 return -ENOSYS;
812#endif
813 } else {
814 switch (opc1) {
815 case 0x50:
816 reg_offset = offsetof(struct pt_regs, ax);
817 break;
818 case 0x51:
819 reg_offset = offsetof(struct pt_regs, cx);
820 break;
821 case 0x52:
822 reg_offset = offsetof(struct pt_regs, dx);
823 break;
824 case 0x53:
825 reg_offset = offsetof(struct pt_regs, bx);
826 break;
827 case 0x54:
828 reg_offset = offsetof(struct pt_regs, sp);
829 break;
830 case 0x55:
831 reg_offset = offsetof(struct pt_regs, bp);
832 break;
833 case 0x56:
834 reg_offset = offsetof(struct pt_regs, si);
835 break;
836 case 0x57:
837 reg_offset = offsetof(struct pt_regs, di);
838 break;
839 }
840 }
841
842 auprobe->push.reg_offset = reg_offset;
843 auprobe->push.ilen = insn->length;
844 auprobe->ops = &push_xol_ops;
845 return 0;
846}
847
753/** 848/**
754 * arch_uprobe_analyze_insn - instruction analysis including validity and fixups. 849 * arch_uprobe_analyze_insn - instruction analysis including validity and fixups.
755 * @mm: the probed address space. 850 * @mm: the probed address space.
@@ -771,6 +866,10 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
771 if (ret != -ENOSYS) 866 if (ret != -ENOSYS)
772 return ret; 867 return ret;
773 868
869 ret = push_setup_xol_ops(auprobe, &insn);
870 if (ret != -ENOSYS)
871 return ret;
872
774 /* 873 /*
775 * Figure out which fixups default_post_xol_op() will need to perform, 874 * Figure out which fixups default_post_xol_op() will need to perform,
776 * and annotate defparam->fixups accordingly. 875 * and annotate defparam->fixups accordingly.