[PATCH] MIPS: Avoid clobbering struct pt_regs in kthreads.

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

 



The resume() implementation octeon_switch.S examines the saved
cp0_status register.  We were clobbering the entire pt_regs structure
in kernel threads leading to random crashes.

When switching away from a kernel thread, the saved cp0_status is
examined and if bit 30 is set it is cleared and the CP2 state saved
into the pt_regs structure.  Since the kernel thread stack overlaid
the pt_regs structure this resulted in a corrupt stack.  When the
kthread with the corrupt stack was resumed, it could crash if it used
any of the data in the stack that was clobbered.

We fix it by moving the kernel thread stack down so it doesn't overlay
pt_regs.

Signed-off-by: David Daney <ddaney@xxxxxxxxxxxxxxxxxx>
---
 arch/mips/kernel/head.S    |    3 ++-
 arch/mips/kernel/process.c |    4 +++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index 492a0a8..24b41c8 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -188,7 +188,8 @@ NESTED(kernel_entry, 16, sp)			# kernel entry point
 
 	MTC0		zero, CP0_CONTEXT	# clear context register
 	PTR_LA		$28, init_thread_union
-	PTR_LI		sp, _THREAD_SIZE - 32
+	/* Set the SP after an empty pt_regs.  */
+	PTR_LI		sp, _THREAD_SIZE - 32 - PT_SIZE - 32
 	PTR_ADDU	sp, $28
 	set_saved_sp	sp, t0, t1
 	PTR_SUBU	sp, 4 * SZREG		# init stack pointer
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index c09d681..d58a443 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -115,7 +115,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
 {
 	struct thread_info *ti = task_thread_info(p);
 	struct pt_regs *childregs;
-	long childksp;
+	unsigned long childksp;
 	p->set_child_tid = p->clear_child_tid = NULL;
 
 	childksp = (unsigned long)task_stack_page(p) + THREAD_SIZE - 32;
@@ -132,6 +132,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
 
 	/* set up new TSS. */
 	childregs = (struct pt_regs *) childksp - 1;
+	/*  Put the stack after the struct pt_regs.  */
+	childksp = (unsigned long) childregs - 32;
 	*childregs = *regs;
 	childregs->regs[7] = 0;	/* Clear error flag */
 
-- 
1.6.0.6



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

  Powered by Linux