Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6ebe7da2 authored by Chris Zankel's avatar Chris Zankel
Browse files

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: default avatarChris Zankel <chris@zankel.net>
parent cddfcbcd
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -220,8 +220,32 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
	if (user_mode(regs)) {

		childregs->areg[1] = usp;

		/* When sharing memory with the parent thread, the child
		   usually starts on a pristine stack, so we have to reset
		   windowbase, windowstart and wmask.
		   (Note that such a new thread is required to always create
		   an initial call4 frame)
		   The exception is vfork, where the new thread continues to
		   run on the parent's stack until it calls execve. This could
		   be a call8 or call12, which requires a legal stack frame
		   of the previous caller for the overflow handlers to work.
		   (Note that it's always legal to overflow live registers).
		   In this case, ensure to spill at least the stack pointer
		   of that frame. */

		if (clone_flags & CLONE_VM) {
			childregs->wmask = 1;	/* can't share live windows */
			/* check that caller window is live and same stack */
			int len = childregs->wmask & ~0xf;
			if (regs->areg[1] == usp && len != 0) {
				int callinc = (regs->areg[0] >> 30) & 3;
				int caller_ars = XCHAL_NUM_AREGS - callinc * 4;
				put_user(regs->areg[caller_ars+1],
					 (unsigned __user*)(usp - 12));
			}
			childregs->wmask = 1;
			childregs->windowstart = 1;
			childregs->windowbase = 0;
		} else {
			int len = childregs->wmask & ~0xf;
			memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],