diff options
Diffstat (limited to 'arch/x86/kernel/ptrace.c')
-rw-r--r-- | arch/x86/kernel/ptrace.c | 57 |
1 files changed, 36 insertions, 21 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 70c4872cd8aa..807c2a2b80f1 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -608,6 +608,9 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data) | |||
608 | unsigned len, type; | 608 | unsigned len, type; |
609 | struct perf_event *bp; | 609 | struct perf_event *bp; |
610 | 610 | ||
611 | if (ptrace_get_breakpoints(tsk) < 0) | ||
612 | return -ESRCH; | ||
613 | |||
611 | data &= ~DR_CONTROL_RESERVED; | 614 | data &= ~DR_CONTROL_RESERVED; |
612 | old_dr7 = ptrace_get_dr7(thread->ptrace_bps); | 615 | old_dr7 = ptrace_get_dr7(thread->ptrace_bps); |
613 | restore: | 616 | restore: |
@@ -655,6 +658,9 @@ restore: | |||
655 | } | 658 | } |
656 | goto restore; | 659 | goto restore; |
657 | } | 660 | } |
661 | |||
662 | ptrace_put_breakpoints(tsk); | ||
663 | |||
658 | return ((orig_ret < 0) ? orig_ret : rc); | 664 | return ((orig_ret < 0) ? orig_ret : rc); |
659 | } | 665 | } |
660 | 666 | ||
@@ -668,10 +674,17 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n) | |||
668 | 674 | ||
669 | if (n < HBP_NUM) { | 675 | if (n < HBP_NUM) { |
670 | struct perf_event *bp; | 676 | struct perf_event *bp; |
677 | |||
678 | if (ptrace_get_breakpoints(tsk) < 0) | ||
679 | return -ESRCH; | ||
680 | |||
671 | bp = thread->ptrace_bps[n]; | 681 | bp = thread->ptrace_bps[n]; |
672 | if (!bp) | 682 | if (!bp) |
673 | return 0; | 683 | val = 0; |
674 | val = bp->hw.info.address; | 684 | else |
685 | val = bp->hw.info.address; | ||
686 | |||
687 | ptrace_put_breakpoints(tsk); | ||
675 | } else if (n == 6) { | 688 | } else if (n == 6) { |
676 | val = thread->debugreg6; | 689 | val = thread->debugreg6; |
677 | } else if (n == 7) { | 690 | } else if (n == 7) { |
@@ -686,6 +699,10 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, | |||
686 | struct perf_event *bp; | 699 | struct perf_event *bp; |
687 | struct thread_struct *t = &tsk->thread; | 700 | struct thread_struct *t = &tsk->thread; |
688 | struct perf_event_attr attr; | 701 | struct perf_event_attr attr; |
702 | int err = 0; | ||
703 | |||
704 | if (ptrace_get_breakpoints(tsk) < 0) | ||
705 | return -ESRCH; | ||
689 | 706 | ||
690 | if (!t->ptrace_bps[nr]) { | 707 | if (!t->ptrace_bps[nr]) { |
691 | ptrace_breakpoint_init(&attr); | 708 | ptrace_breakpoint_init(&attr); |
@@ -709,24 +726,23 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, | |||
709 | * writing for the user. And anyway this is the previous | 726 | * writing for the user. And anyway this is the previous |
710 | * behaviour. | 727 | * behaviour. |
711 | */ | 728 | */ |
712 | if (IS_ERR(bp)) | 729 | if (IS_ERR(bp)) { |
713 | return PTR_ERR(bp); | 730 | err = PTR_ERR(bp); |
731 | goto put; | ||
732 | } | ||
714 | 733 | ||
715 | t->ptrace_bps[nr] = bp; | 734 | t->ptrace_bps[nr] = bp; |
716 | } else { | 735 | } else { |
717 | int err; | ||
718 | |||
719 | bp = t->ptrace_bps[nr]; | 736 | bp = t->ptrace_bps[nr]; |
720 | 737 | ||
721 | attr = bp->attr; | 738 | attr = bp->attr; |
722 | attr.bp_addr = addr; | 739 | attr.bp_addr = addr; |
723 | err = modify_user_hw_breakpoint(bp, &attr); | 740 | err = modify_user_hw_breakpoint(bp, &attr); |
724 | if (err) | ||
725 | return err; | ||
726 | } | 741 | } |
727 | 742 | ||
728 | 743 | put: | |
729 | return 0; | 744 | ptrace_put_breakpoints(tsk); |
745 | return err; | ||
730 | } | 746 | } |
731 | 747 | ||
732 | /* | 748 | /* |
@@ -801,7 +817,8 @@ void ptrace_disable(struct task_struct *child) | |||
801 | static const struct user_regset_view user_x86_32_view; /* Initialized below. */ | 817 | static const struct user_regset_view user_x86_32_view; /* Initialized below. */ |
802 | #endif | 818 | #endif |
803 | 819 | ||
804 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 820 | long arch_ptrace(struct task_struct *child, long request, |
821 | unsigned long addr, unsigned long data) | ||
805 | { | 822 | { |
806 | int ret; | 823 | int ret; |
807 | unsigned long __user *datap = (unsigned long __user *)data; | 824 | unsigned long __user *datap = (unsigned long __user *)data; |
@@ -812,8 +829,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
812 | unsigned long tmp; | 829 | unsigned long tmp; |
813 | 830 | ||
814 | ret = -EIO; | 831 | ret = -EIO; |
815 | if ((addr & (sizeof(data) - 1)) || addr < 0 || | 832 | if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user)) |
816 | addr >= sizeof(struct user)) | ||
817 | break; | 833 | break; |
818 | 834 | ||
819 | tmp = 0; /* Default return condition */ | 835 | tmp = 0; /* Default return condition */ |
@@ -830,8 +846,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
830 | 846 | ||
831 | case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ | 847 | case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ |
832 | ret = -EIO; | 848 | ret = -EIO; |
833 | if ((addr & (sizeof(data) - 1)) || addr < 0 || | 849 | if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user)) |
834 | addr >= sizeof(struct user)) | ||
835 | break; | 850 | break; |
836 | 851 | ||
837 | if (addr < sizeof(struct user_regs_struct)) | 852 | if (addr < sizeof(struct user_regs_struct)) |
@@ -888,17 +903,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
888 | 903 | ||
889 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION | 904 | #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION |
890 | case PTRACE_GET_THREAD_AREA: | 905 | case PTRACE_GET_THREAD_AREA: |
891 | if (addr < 0) | 906 | if ((int) addr < 0) |
892 | return -EIO; | 907 | return -EIO; |
893 | ret = do_get_thread_area(child, addr, | 908 | ret = do_get_thread_area(child, addr, |
894 | (struct user_desc __user *) data); | 909 | (struct user_desc __user *)data); |
895 | break; | 910 | break; |
896 | 911 | ||
897 | case PTRACE_SET_THREAD_AREA: | 912 | case PTRACE_SET_THREAD_AREA: |
898 | if (addr < 0) | 913 | if ((int) addr < 0) |
899 | return -EIO; | 914 | return -EIO; |
900 | ret = do_set_thread_area(child, addr, | 915 | ret = do_set_thread_area(child, addr, |
901 | (struct user_desc __user *) data, 0); | 916 | (struct user_desc __user *)data, 0); |
902 | break; | 917 | break; |
903 | #endif | 918 | #endif |
904 | 919 | ||
@@ -1348,7 +1363,7 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, | |||
1348 | * We must return the syscall number to actually look up in the table. | 1363 | * We must return the syscall number to actually look up in the table. |
1349 | * This can be -1L to skip running any syscall at all. | 1364 | * This can be -1L to skip running any syscall at all. |
1350 | */ | 1365 | */ |
1351 | asmregparm long syscall_trace_enter(struct pt_regs *regs) | 1366 | long syscall_trace_enter(struct pt_regs *regs) |
1352 | { | 1367 | { |
1353 | long ret = 0; | 1368 | long ret = 0; |
1354 | 1369 | ||
@@ -1393,7 +1408,7 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs) | |||
1393 | return ret ?: regs->orig_ax; | 1408 | return ret ?: regs->orig_ax; |
1394 | } | 1409 | } |
1395 | 1410 | ||
1396 | asmregparm void syscall_trace_leave(struct pt_regs *regs) | 1411 | void syscall_trace_leave(struct pt_regs *regs) |
1397 | { | 1412 | { |
1398 | bool step; | 1413 | bool step; |
1399 | 1414 | ||