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.c57
1 files changed, 26 insertions, 31 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index b361d28061d0..7079ddaf0731 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -595,7 +595,7 @@ static unsigned long ptrace_get_dr7(struct perf_event *bp[])
595 return dr7; 595 return dr7;
596} 596}
597 597
598static struct perf_event * 598static int
599ptrace_modify_breakpoint(struct perf_event *bp, int len, int type, 599ptrace_modify_breakpoint(struct perf_event *bp, int len, int type,
600 struct task_struct *tsk, int disabled) 600 struct task_struct *tsk, int disabled)
601{ 601{
@@ -609,11 +609,11 @@ ptrace_modify_breakpoint(struct perf_event *bp, int len, int type,
609 * written the address register first 609 * written the address register first
610 */ 610 */
611 if (!bp) 611 if (!bp)
612 return ERR_PTR(-EINVAL); 612 return -EINVAL;
613 613
614 err = arch_bp_generic_fields(len, type, &gen_len, &gen_type); 614 err = arch_bp_generic_fields(len, type, &gen_len, &gen_type);
615 if (err) 615 if (err)
616 return ERR_PTR(err); 616 return err;
617 617
618 attr = bp->attr; 618 attr = bp->attr;
619 attr.bp_len = gen_len; 619 attr.bp_len = gen_len;
@@ -658,28 +658,17 @@ restore:
658 if (!second_pass) 658 if (!second_pass)
659 continue; 659 continue;
660 660
661 thread->ptrace_bps[i] = NULL; 661 rc = ptrace_modify_breakpoint(bp, len, type,
662 bp = ptrace_modify_breakpoint(bp, len, type,
663 tsk, 1); 662 tsk, 1);
664 if (IS_ERR(bp)) { 663 if (rc)
665 rc = PTR_ERR(bp);
666 thread->ptrace_bps[i] = NULL;
667 break; 664 break;
668 }
669 thread->ptrace_bps[i] = bp;
670 } 665 }
671 continue; 666 continue;
672 } 667 }
673 668
674 bp = ptrace_modify_breakpoint(bp, len, type, tsk, 0); 669 rc = ptrace_modify_breakpoint(bp, len, type, tsk, 0);
675 670 if (rc)
676 /* Incorrect bp, or we have a bug in bp API */
677 if (IS_ERR(bp)) {
678 rc = PTR_ERR(bp);
679 thread->ptrace_bps[i] = NULL;
680 break; 671 break;
681 }
682 thread->ptrace_bps[i] = bp;
683 } 672 }
684 /* 673 /*
685 * Make a second pass to free the remaining unused breakpoints 674 * Make a second pass to free the remaining unused breakpoints
@@ -737,26 +726,32 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
737 attr.disabled = 1; 726 attr.disabled = 1;
738 727
739 bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk); 728 bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk);
729
730 /*
731 * CHECKME: the previous code returned -EIO if the addr wasn't
732 * a valid task virtual addr. The new one will return -EINVAL in
733 * this case.
734 * -EINVAL may be what we want for in-kernel breakpoints users,
735 * but -EIO looks better for ptrace, since we refuse a register
736 * writing for the user. And anyway this is the previous
737 * behaviour.
738 */
739 if (IS_ERR(bp))
740 return PTR_ERR(bp);
741
742 t->ptrace_bps[nr] = bp;
740 } else { 743 } else {
744 int err;
745
741 bp = t->ptrace_bps[nr]; 746 bp = t->ptrace_bps[nr];
742 t->ptrace_bps[nr] = NULL;
743 747
744 attr = bp->attr; 748 attr = bp->attr;
745 attr.bp_addr = addr; 749 attr.bp_addr = addr;
746 bp = modify_user_hw_breakpoint(bp, &attr); 750 err = modify_user_hw_breakpoint(bp, &attr);
751 if (err)
752 return err;
747 } 753 }
748 /*
749 * CHECKME: the previous code returned -EIO if the addr wasn't a
750 * valid task virtual addr. The new one will return -EINVAL in this
751 * case.
752 * -EINVAL may be what we want for in-kernel breakpoints users, but
753 * -EIO looks better for ptrace, since we refuse a register writing
754 * for the user. And anyway this is the previous behaviour.
755 */
756 if (IS_ERR(bp))
757 return PTR_ERR(bp);
758 754
759 t->ptrace_bps[nr] = bp;
760 755
761 return 0; 756 return 0;
762} 757}