From: Heiher <r@xxxxxx> The following program cause an endless loop in kernel space: #include <stdio.h> #include <unistd.h> #include <signal.h> int main (int argc, char *argv[]) { char buf[16]; printf ("%p\n", buf); raise (SIGINT); write (1, buf, 16); return 0; } # gcc -O0 -o t t.c # gdb ./t (gdb) r (gdb) watch *<printed buf address> (gdb) c Signed-off-by: Heiher <r@xxxxxx> --- arch/mips/kernel/entry.S | 23 +++++++++++++++++++++++ arch/mips/kernel/traps.c | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index 38a302919e6b..6094844fc63f 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -49,6 +49,13 @@ resume_userspace: # interrupt setting need_resched # between sampling and return LONG_L a2, TI_FLAGS($28) # current->work + li t0, _TIF_LOAD_WATCH + and t0, a2 + beqz t0, 1f + move a0, $28 + jal mips_install_watch_registers + LONG_L a2, TI_FLAGS($28) # current->work +1: andi t0, a2, _TIF_WORK_MASK # (ignoring syscall_trace) bnez t0, work_pending j restore_all @@ -82,7 +89,15 @@ FEXPORT(syscall_exit) local_irq_disable # make sure need_resched and # signals dont change between # sampling and return + + LONG_L a2, TI_FLAGS($28) # current->work + li t0, _TIF_LOAD_WATCH + and t0, a2 + beqz t0, 1f + move a0, $28 + jal mips_install_watch_registers LONG_L a2, TI_FLAGS($28) # current->work +1: li t0, _TIF_ALLWORK_MASK and t0, a2, t0 bnez t0, syscall_exit_work @@ -143,7 +158,15 @@ work_notifysig: # deal with pending signals and FEXPORT(syscall_exit_partial) local_irq_disable # make sure need_resched doesn't # change between and return + + LONG_L a2, TI_FLAGS($28) # current->work + li t0, _TIF_LOAD_WATCH + and t0, a2 + beqz t0, 1f + move a0, $28 + jal mips_install_watch_registers LONG_L a2, TI_FLAGS($28) # current->work +1: li t0, _TIF_ALLWORK_MASK and t0, a2 beqz t0, restore_partial diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 967e9e4e795e..22f671263b27 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1525,7 +1525,7 @@ asmlinkage void do_watch(struct pt_regs *regs) * their values and send SIGTRAP. Otherwise another thread * left the registers set, clear them and continue. */ - if (test_tsk_thread_flag(current, TIF_LOAD_WATCH)) { + if (user_mode(regs) && test_tsk_thread_flag(current, TIF_LOAD_WATCH)) { mips_read_watch_registers(); local_irq_enable(); force_sig_info(SIGTRAP, &info, current); -- 2.16.3