aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Zankel <chris@zankel.net>2012-10-24 16:15:21 -0400
committerChris Zankel <chris@zankel.net>2012-10-25 17:53:36 -0400
commit6ebe7da25b7879194fdb5c43ea67b383dd9014d6 (patch)
tree078aca917e5fe9db80af42298210684d250f98bf
parentcddfcbcd05851a3b720055d40fc61c63ea1c2bd1 (diff)
xtensa: reset windowbase/windowstart when cloning the VM
When we copy a user thread with CLONE_VM, we also have to reset windowbase and windowstart to start a pristine stack frame. Otherwise, overflows can happen using the address 0 as the stack pointer. Also add a special case for vfork, which continues on the parent stack until it calls execve. Because this could be a call8, we need to spill the stack pointer of the previus frame (if still 'live' in the register file). Signed-off-by: Chris Zankel <chris@zankel.net>
-rw-r--r--arch/xtensa/kernel/process.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index 1908f6642d31..341c151af919 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -220,8 +220,32 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
220 if (user_mode(regs)) { 220 if (user_mode(regs)) {
221 221
222 childregs->areg[1] = usp; 222 childregs->areg[1] = usp;
223
224 /* When sharing memory with the parent thread, the child
225 usually starts on a pristine stack, so we have to reset
226 windowbase, windowstart and wmask.
227 (Note that such a new thread is required to always create
228 an initial call4 frame)
229 The exception is vfork, where the new thread continues to
230 run on the parent's stack until it calls execve. This could
231 be a call8 or call12, which requires a legal stack frame
232 of the previous caller for the overflow handlers to work.
233 (Note that it's always legal to overflow live registers).
234 In this case, ensure to spill at least the stack pointer
235 of that frame. */
236
223 if (clone_flags & CLONE_VM) { 237 if (clone_flags & CLONE_VM) {
224 childregs->wmask = 1; /* can't share live windows */ 238 /* check that caller window is live and same stack */
239 int len = childregs->wmask & ~0xf;
240 if (regs->areg[1] == usp && len != 0) {
241 int callinc = (regs->areg[0] >> 30) & 3;
242 int caller_ars = XCHAL_NUM_AREGS - callinc * 4;
243 put_user(regs->areg[caller_ars+1],
244 (unsigned __user*)(usp - 12));
245 }
246 childregs->wmask = 1;
247 childregs->windowstart = 1;
248 childregs->windowbase = 0;
225 } else { 249 } else {
226 int len = childregs->wmask & ~0xf; 250 int len = childregs->wmask & ~0xf;
227 memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4], 251 memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],