[PATCH] MIPS: Avoid to cause watchpoint exception in kernel mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux