aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/ptrace.c')
-rw-r--r--arch/x86/kernel/ptrace.c74
1 files changed, 41 insertions, 33 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 75e0cd847bd6..2941b32ea666 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -593,6 +593,34 @@ static unsigned long ptrace_get_dr7(struct perf_event *bp[])
593 return dr7; 593 return dr7;
594} 594}
595 595
596static struct perf_event *
597ptrace_modify_breakpoint(struct perf_event *bp, int len, int type,
598 struct task_struct *tsk)
599{
600 int err;
601 int gen_len, gen_type;
602 DEFINE_BREAKPOINT_ATTR(attr);
603
604 /*
605 * We shoud have at least an inactive breakpoint at this
606 * slot. It means the user is writing dr7 without having
607 * written the address register first
608 */
609 if (!bp)
610 return ERR_PTR(-EINVAL);
611
612 err = arch_bp_generic_fields(len, type, &gen_len, &gen_type);
613 if (err)
614 return ERR_PTR(err);
615
616 attr = bp->attr;
617 attr.bp_len = gen_len;
618 attr.bp_type = gen_type;
619 attr.disabled = 0;
620
621 return modify_user_hw_breakpoint(bp, &attr, bp->callback, tsk);
622}
623
596/* 624/*
597 * Handle ptrace writes to debug register 7. 625 * Handle ptrace writes to debug register 7.
598 */ 626 */
@@ -603,7 +631,6 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data)
603 int i, orig_ret = 0, rc = 0; 631 int i, orig_ret = 0, rc = 0;
604 int enabled, second_pass = 0; 632 int enabled, second_pass = 0;
605 unsigned len, type; 633 unsigned len, type;
606 int gen_len, gen_type;
607 struct perf_event *bp; 634 struct perf_event *bp;
608 635
609 data &= ~DR_CONTROL_RESERVED; 636 data &= ~DR_CONTROL_RESERVED;
@@ -634,33 +661,12 @@ restore:
634 continue; 661 continue;
635 } 662 }
636 663
637 /* 664 bp = ptrace_modify_breakpoint(bp, len, type, tsk);
638 * We shoud have at least an inactive breakpoint at this
639 * slot. It means the user is writing dr7 without having
640 * written the address register first
641 */
642 if (!bp) {
643 rc = -EINVAL;
644 break;
645 }
646
647 rc = arch_bp_generic_fields(len, type, &gen_len, &gen_type);
648 if (rc)
649 break;
650
651 /*
652 * This is a temporary thing as bp is unregistered/registered
653 * to simulate modification
654 */
655 bp = modify_user_hw_breakpoint(bp, bp->attr.bp_addr, gen_len,
656 gen_type, bp->callback,
657 tsk, true);
658 thread->ptrace_bps[i] = NULL;
659 665
660 /* Incorrect bp, or we have a bug in bp API */ 666 /* Incorrect bp, or we have a bug in bp API */
661 if (IS_ERR(bp)) { 667 if (IS_ERR(bp)) {
662 rc = PTR_ERR(bp); 668 rc = PTR_ERR(bp);
663 bp = NULL; 669 thread->ptrace_bps[i] = NULL;
664 break; 670 break;
665 } 671 }
666 thread->ptrace_bps[i] = bp; 672 thread->ptrace_bps[i] = bp;
@@ -707,24 +713,26 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
707{ 713{
708 struct perf_event *bp; 714 struct perf_event *bp;
709 struct thread_struct *t = &tsk->thread; 715 struct thread_struct *t = &tsk->thread;
716 DEFINE_BREAKPOINT_ATTR(attr);
710 717
711 if (!t->ptrace_bps[nr]) { 718 if (!t->ptrace_bps[nr]) {
712 /* 719 /*
713 * Put stub len and type to register (reserve) an inactive but 720 * Put stub len and type to register (reserve) an inactive but
714 * correct bp 721 * correct bp
715 */ 722 */
716 bp = register_user_hw_breakpoint(addr, HW_BREAKPOINT_LEN_1, 723 attr.bp_addr = addr;
717 HW_BREAKPOINT_W, 724 attr.bp_len = HW_BREAKPOINT_LEN_1;
718 ptrace_triggered, tsk, 725 attr.bp_type = HW_BREAKPOINT_W;
719 false); 726 attr.disabled = 1;
727
728 bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk);
720 } else { 729 } else {
721 bp = t->ptrace_bps[nr]; 730 bp = t->ptrace_bps[nr];
722 t->ptrace_bps[nr] = NULL; 731 t->ptrace_bps[nr] = NULL;
723 bp = modify_user_hw_breakpoint(bp, addr, bp->attr.bp_len, 732
724 bp->attr.bp_type, 733 attr = bp->attr;
725 bp->callback, 734 attr.bp_addr = addr;
726 tsk, 735 bp = modify_user_hw_breakpoint(bp, &attr, bp->callback, tsk);
727 bp->attr.disabled);
728 } 736 }
729 /* 737 /*
730 * CHECKME: the previous code returned -EIO if the addr wasn't a 738 * CHECKME: the previous code returned -EIO if the addr wasn't a