Loading arch/arm/kernel/ptrace.c +8 −0 Original line number Original line Diff line number Diff line Loading @@ -767,12 +767,20 @@ long arch_ptrace(struct task_struct *child, long request, #ifdef CONFIG_HAVE_HW_BREAKPOINT #ifdef CONFIG_HAVE_HW_BREAKPOINT case PTRACE_GETHBPREGS: case PTRACE_GETHBPREGS: if (ptrace_get_breakpoints(child) < 0) return -ESRCH; ret = ptrace_gethbpregs(child, addr, ret = ptrace_gethbpregs(child, addr, (unsigned long __user *)data); (unsigned long __user *)data); ptrace_put_breakpoints(child); break; break; case PTRACE_SETHBPREGS: case PTRACE_SETHBPREGS: if (ptrace_get_breakpoints(child) < 0) return -ESRCH; ret = ptrace_sethbpregs(child, addr, ret = ptrace_sethbpregs(child, addr, (unsigned long __user *)data); (unsigned long __user *)data); ptrace_put_breakpoints(child); break; break; #endif #endif Loading arch/powerpc/kernel/ptrace.c +3 −0 Original line number Original line Diff line number Diff line Loading @@ -1591,7 +1591,10 @@ long arch_ptrace(struct task_struct *child, long request, } } case PTRACE_SET_DEBUGREG: case PTRACE_SET_DEBUGREG: if (ptrace_get_breakpoints(child) < 0) return -ESRCH; ret = ptrace_set_debugreg(child, addr, data); ret = ptrace_set_debugreg(child, addr, data); ptrace_put_breakpoints(child); break; break; #ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64 Loading arch/sh/kernel/ptrace_32.c +4 −0 Original line number Original line Diff line number Diff line Loading @@ -117,7 +117,11 @@ void user_enable_single_step(struct task_struct *child) set_tsk_thread_flag(child, TIF_SINGLESTEP); set_tsk_thread_flag(child, TIF_SINGLESTEP); if (ptrace_get_breakpoints(child) < 0) return; set_single_step(child, pc); set_single_step(child, pc); ptrace_put_breakpoints(child); } } void user_disable_single_step(struct task_struct *child) void user_disable_single_step(struct task_struct *child) Loading arch/x86/kernel/ptrace.c +26 −10 Original line number Original line Diff line number Diff line Loading @@ -608,6 +608,9 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data) unsigned len, type; unsigned len, type; struct perf_event *bp; struct perf_event *bp; if (ptrace_get_breakpoints(tsk) < 0) return -ESRCH; data &= ~DR_CONTROL_RESERVED; data &= ~DR_CONTROL_RESERVED; old_dr7 = ptrace_get_dr7(thread->ptrace_bps); old_dr7 = ptrace_get_dr7(thread->ptrace_bps); restore: restore: Loading Loading @@ -655,6 +658,9 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data) } } goto restore; goto restore; } } ptrace_put_breakpoints(tsk); return ((orig_ret < 0) ? orig_ret : rc); return ((orig_ret < 0) ? orig_ret : rc); } } Loading @@ -668,10 +674,17 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n) if (n < HBP_NUM) { if (n < HBP_NUM) { struct perf_event *bp; struct perf_event *bp; if (ptrace_get_breakpoints(tsk) < 0) return -ESRCH; bp = thread->ptrace_bps[n]; bp = thread->ptrace_bps[n]; if (!bp) if (!bp) return 0; val = 0; else val = bp->hw.info.address; val = bp->hw.info.address; ptrace_put_breakpoints(tsk); } else if (n == 6) { } else if (n == 6) { val = thread->debugreg6; val = thread->debugreg6; } else if (n == 7) { } else if (n == 7) { Loading @@ -686,6 +699,10 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, struct perf_event *bp; struct perf_event *bp; struct thread_struct *t = &tsk->thread; struct thread_struct *t = &tsk->thread; struct perf_event_attr attr; struct perf_event_attr attr; int err = 0; if (ptrace_get_breakpoints(tsk) < 0) return -ESRCH; if (!t->ptrace_bps[nr]) { if (!t->ptrace_bps[nr]) { ptrace_breakpoint_init(&attr); ptrace_breakpoint_init(&attr); Loading @@ -709,24 +726,23 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, * writing for the user. And anyway this is the previous * writing for the user. And anyway this is the previous * behaviour. * behaviour. */ */ if (IS_ERR(bp)) if (IS_ERR(bp)) { return PTR_ERR(bp); err = PTR_ERR(bp); goto put; } t->ptrace_bps[nr] = bp; t->ptrace_bps[nr] = bp; } else { } else { int err; bp = t->ptrace_bps[nr]; bp = t->ptrace_bps[nr]; attr = bp->attr; attr = bp->attr; attr.bp_addr = addr; attr.bp_addr = addr; err = modify_user_hw_breakpoint(bp, &attr); err = modify_user_hw_breakpoint(bp, &attr); if (err) return err; } } put: return 0; ptrace_put_breakpoints(tsk); return err; } } /* /* Loading include/linux/ptrace.h +12 −1 Original line number Original line Diff line number Diff line Loading @@ -189,6 +189,10 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace) child->ptrace = current->ptrace; child->ptrace = current->ptrace; __ptrace_link(child, current->parent); __ptrace_link(child, current->parent); } } #ifdef CONFIG_HAVE_HW_BREAKPOINT atomic_set(&child->ptrace_bp_refcnt, 1); #endif } } /** /** Loading Loading @@ -350,6 +354,13 @@ extern int task_current_syscall(struct task_struct *target, long *callno, unsigned long args[6], unsigned int maxargs, unsigned long args[6], unsigned int maxargs, unsigned long *sp, unsigned long *pc); unsigned long *sp, unsigned long *pc); #endif #ifdef CONFIG_HAVE_HW_BREAKPOINT extern int ptrace_get_breakpoints(struct task_struct *tsk); extern void ptrace_put_breakpoints(struct task_struct *tsk); #else static inline void ptrace_put_breakpoints(struct task_struct *tsk) { } #endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif /* __KERNEL */ #endif #endif Loading
arch/arm/kernel/ptrace.c +8 −0 Original line number Original line Diff line number Diff line Loading @@ -767,12 +767,20 @@ long arch_ptrace(struct task_struct *child, long request, #ifdef CONFIG_HAVE_HW_BREAKPOINT #ifdef CONFIG_HAVE_HW_BREAKPOINT case PTRACE_GETHBPREGS: case PTRACE_GETHBPREGS: if (ptrace_get_breakpoints(child) < 0) return -ESRCH; ret = ptrace_gethbpregs(child, addr, ret = ptrace_gethbpregs(child, addr, (unsigned long __user *)data); (unsigned long __user *)data); ptrace_put_breakpoints(child); break; break; case PTRACE_SETHBPREGS: case PTRACE_SETHBPREGS: if (ptrace_get_breakpoints(child) < 0) return -ESRCH; ret = ptrace_sethbpregs(child, addr, ret = ptrace_sethbpregs(child, addr, (unsigned long __user *)data); (unsigned long __user *)data); ptrace_put_breakpoints(child); break; break; #endif #endif Loading
arch/powerpc/kernel/ptrace.c +3 −0 Original line number Original line Diff line number Diff line Loading @@ -1591,7 +1591,10 @@ long arch_ptrace(struct task_struct *child, long request, } } case PTRACE_SET_DEBUGREG: case PTRACE_SET_DEBUGREG: if (ptrace_get_breakpoints(child) < 0) return -ESRCH; ret = ptrace_set_debugreg(child, addr, data); ret = ptrace_set_debugreg(child, addr, data); ptrace_put_breakpoints(child); break; break; #ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64 Loading
arch/sh/kernel/ptrace_32.c +4 −0 Original line number Original line Diff line number Diff line Loading @@ -117,7 +117,11 @@ void user_enable_single_step(struct task_struct *child) set_tsk_thread_flag(child, TIF_SINGLESTEP); set_tsk_thread_flag(child, TIF_SINGLESTEP); if (ptrace_get_breakpoints(child) < 0) return; set_single_step(child, pc); set_single_step(child, pc); ptrace_put_breakpoints(child); } } void user_disable_single_step(struct task_struct *child) void user_disable_single_step(struct task_struct *child) Loading
arch/x86/kernel/ptrace.c +26 −10 Original line number Original line Diff line number Diff line Loading @@ -608,6 +608,9 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data) unsigned len, type; unsigned len, type; struct perf_event *bp; struct perf_event *bp; if (ptrace_get_breakpoints(tsk) < 0) return -ESRCH; data &= ~DR_CONTROL_RESERVED; data &= ~DR_CONTROL_RESERVED; old_dr7 = ptrace_get_dr7(thread->ptrace_bps); old_dr7 = ptrace_get_dr7(thread->ptrace_bps); restore: restore: Loading Loading @@ -655,6 +658,9 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data) } } goto restore; goto restore; } } ptrace_put_breakpoints(tsk); return ((orig_ret < 0) ? orig_ret : rc); return ((orig_ret < 0) ? orig_ret : rc); } } Loading @@ -668,10 +674,17 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n) if (n < HBP_NUM) { if (n < HBP_NUM) { struct perf_event *bp; struct perf_event *bp; if (ptrace_get_breakpoints(tsk) < 0) return -ESRCH; bp = thread->ptrace_bps[n]; bp = thread->ptrace_bps[n]; if (!bp) if (!bp) return 0; val = 0; else val = bp->hw.info.address; val = bp->hw.info.address; ptrace_put_breakpoints(tsk); } else if (n == 6) { } else if (n == 6) { val = thread->debugreg6; val = thread->debugreg6; } else if (n == 7) { } else if (n == 7) { Loading @@ -686,6 +699,10 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, struct perf_event *bp; struct perf_event *bp; struct thread_struct *t = &tsk->thread; struct thread_struct *t = &tsk->thread; struct perf_event_attr attr; struct perf_event_attr attr; int err = 0; if (ptrace_get_breakpoints(tsk) < 0) return -ESRCH; if (!t->ptrace_bps[nr]) { if (!t->ptrace_bps[nr]) { ptrace_breakpoint_init(&attr); ptrace_breakpoint_init(&attr); Loading @@ -709,24 +726,23 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, * writing for the user. And anyway this is the previous * writing for the user. And anyway this is the previous * behaviour. * behaviour. */ */ if (IS_ERR(bp)) if (IS_ERR(bp)) { return PTR_ERR(bp); err = PTR_ERR(bp); goto put; } t->ptrace_bps[nr] = bp; t->ptrace_bps[nr] = bp; } else { } else { int err; bp = t->ptrace_bps[nr]; bp = t->ptrace_bps[nr]; attr = bp->attr; attr = bp->attr; attr.bp_addr = addr; attr.bp_addr = addr; err = modify_user_hw_breakpoint(bp, &attr); err = modify_user_hw_breakpoint(bp, &attr); if (err) return err; } } put: return 0; ptrace_put_breakpoints(tsk); return err; } } /* /* Loading
include/linux/ptrace.h +12 −1 Original line number Original line Diff line number Diff line Loading @@ -189,6 +189,10 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace) child->ptrace = current->ptrace; child->ptrace = current->ptrace; __ptrace_link(child, current->parent); __ptrace_link(child, current->parent); } } #ifdef CONFIG_HAVE_HW_BREAKPOINT atomic_set(&child->ptrace_bp_refcnt, 1); #endif } } /** /** Loading Loading @@ -350,6 +354,13 @@ extern int task_current_syscall(struct task_struct *target, long *callno, unsigned long args[6], unsigned int maxargs, unsigned long args[6], unsigned int maxargs, unsigned long *sp, unsigned long *pc); unsigned long *sp, unsigned long *pc); #endif #ifdef CONFIG_HAVE_HW_BREAKPOINT extern int ptrace_get_breakpoints(struct task_struct *tsk); extern void ptrace_put_breakpoints(struct task_struct *tsk); #else static inline void ptrace_put_breakpoints(struct task_struct *tsk) { } #endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif /* __KERNEL */ #endif #endif