diff options
author | Ravi Bangoria <ravi.bangoria@linux.ibm.com> | 2020-09-02 09:59:42 +0530 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2020-09-15 22:13:20 +1000 |
commit | 5b905d77987de065bdd3a2906816b5f143df087b (patch) | |
tree | 0c35d7c18b1d8902425b792d1102835ca582af13 /arch/powerpc/kernel/ptrace | |
parent | edc8dd99b29e4d705c45e2a3a6c01b096ee056db (diff) | |
download | lwn-5b905d77987de065bdd3a2906816b5f143df087b.tar.gz lwn-5b905d77987de065bdd3a2906816b5f143df087b.zip |
powerpc/watchpoint: Fix exception handling for CONFIG_HAVE_HW_BREAKPOINT=N
On powerpc, ptrace watchpoint works in one-shot mode. i.e. kernel
disables event every time it fires and user has to re-enable it.
Also, in case of ptrace watchpoint, kernel notifies ptrace user
before executing instruction.
With CONFIG_HAVE_HW_BREAKPOINT=N, kernel is missing to disable
ptrace event and thus it's causing infinite loop of exceptions.
This is especially harmful when user watches on a data which is
also read/written by kernel, eg syscall parameters. In such case,
infinite exceptions happens in kernel mode which causes soft-lockup.
Fixes: 9422de3e953d ("powerpc: Hardware breakpoints rewrite to handle non DABR breakpoint registers")
Reported-by: Pedro Miraglia Franco de Carvalho <pedromfc@linux.ibm.com>
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200902042945.129369-6-ravi.bangoria@linux.ibm.com
Diffstat (limited to 'arch/powerpc/kernel/ptrace')
-rw-r--r-- | arch/powerpc/kernel/ptrace/ptrace-noadv.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/ptrace/ptrace-noadv.c b/arch/powerpc/kernel/ptrace/ptrace-noadv.c index 57a0ab822334..c9122ed91340 100644 --- a/arch/powerpc/kernel/ptrace/ptrace-noadv.c +++ b/arch/powerpc/kernel/ptrace/ptrace-noadv.c @@ -286,11 +286,13 @@ long ppc_del_hwdebug(struct task_struct *child, long data) } return ret; #else /* CONFIG_HAVE_HW_BREAKPOINT */ - if (child->thread.hw_brk[data - 1].address == 0) + if (!(child->thread.hw_brk[data - 1].flags & HW_BRK_FLAG_DISABLED) && + child->thread.hw_brk[data - 1].address == 0) return -ENOENT; child->thread.hw_brk[data - 1].address = 0; child->thread.hw_brk[data - 1].type = 0; + child->thread.hw_brk[data - 1].flags = 0; #endif /* CONFIG_HAVE_HW_BREAKPOINT */ return 0; |