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

Commit 0a592281 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile:
  arch/tile: handle rt_sigreturn() more cleanly
  arch/tile: handle CLONE_SETTLS in copy_thread(), not user space
parents 2ba16c4f 81711cee
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@

#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
struct pt_regs;
int restore_sigcontext(struct pt_regs *, struct sigcontext __user *, long *);
int restore_sigcontext(struct pt_regs *, struct sigcontext __user *);
int setup_sigcontext(struct sigcontext __user *, struct pt_regs *);
void do_signal(struct pt_regs *regs);
#endif
+3 −3
Original line number Diff line number Diff line
@@ -290,12 +290,12 @@ long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
	return ret;
}

/* The assembly shim for this function arranges to ignore the return value. */
long compat_sys_rt_sigreturn(struct pt_regs *regs)
{
	struct compat_rt_sigframe __user *frame =
		(struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
	sigset_t set;
	long r0;

	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
		goto badframe;
@@ -308,13 +308,13 @@ long compat_sys_rt_sigreturn(struct pt_regs *regs)
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);

	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
		goto badframe;

	if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
		goto badframe;

	return r0;
	return 0;

badframe:
	force_sig(SIGSEGV, current);
+21 −3
Original line number Diff line number Diff line
@@ -1342,8 +1342,8 @@ handle_syscall:
	lw      r20, r20

	/* Jump to syscall handler. */
	jalr    r20; .Lhandle_syscall_link:
	FEEDBACK_REENTER(handle_syscall)
	jalr    r20
.Lhandle_syscall_link: /* value of "lr" after "jalr r20" above */

	/*
	 * Write our r0 onto the stack so it gets restored instead
@@ -1352,6 +1352,9 @@ handle_syscall:
	PTREGS_PTR(r29, PTREGS_OFFSET_REG(0))
	sw      r29, r0

.Lsyscall_sigreturn_skip:
	FEEDBACK_REENTER(handle_syscall)

	/* Do syscall trace again, if requested. */
	lw	r30, r31
	andi    r30, r30, _TIF_SYSCALL_TRACE
@@ -1536,9 +1539,24 @@ STD_ENTRY_LOCAL(bad_intr)
	};                                              \
	STD_ENDPROC(_##x)

/*
 * Special-case sigreturn to not write r0 to the stack on return.
 * This is technically more efficient, but it also avoids difficulties
 * in the 64-bit OS when handling 32-bit compat code, since we must not
 * sign-extend r0 for the sigreturn return-value case.
 */
#define PTREGS_SYSCALL_SIGRETURN(x, reg)                \
	STD_ENTRY(_##x);                                \
	addli   lr, lr, .Lsyscall_sigreturn_skip - .Lhandle_syscall_link; \
	{                                               \
	 PTREGS_PTR(reg, PTREGS_OFFSET_BASE);           \
	 j      x                                       \
	};                                              \
	STD_ENDPROC(_##x)

PTREGS_SYSCALL(sys_execve, r3)
PTREGS_SYSCALL(sys_sigaltstack, r2)
PTREGS_SYSCALL(sys_rt_sigreturn, r0)
PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0)
PTREGS_SYSCALL(sys_cmpxchg_badaddr, r1)

/* Save additional callee-saves to pt_regs, put address in r4 and jump. */
+8 −0
Original line number Diff line number Diff line
@@ -211,6 +211,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
	childregs->regs[0] = 0;         /* return value is zero */
	childregs->sp = sp;  /* override with new user stack pointer */

	/*
	 * If CLONE_SETTLS is set, set "tp" in the new task to "r4",
	 * which is passed in as arg #5 to sys_clone().
	 */
	if (clone_flags & CLONE_SETTLS)
		childregs->tp = regs->regs[4];

	/*
	 * Copy the callee-saved registers from the passed pt_regs struct
	 * into the context-switch callee-saved registers area.
@@ -539,6 +546,7 @@ struct task_struct *__sched _switch_to(struct task_struct *prev,
	return __switch_to(prev, next, next_current_ksp0(next));
}

/* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */
SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
		void __user *, parent_tidptr, void __user *, child_tidptr,
		struct pt_regs *, regs)
+4 −6
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss,
 */

int restore_sigcontext(struct pt_regs *regs,
		       struct sigcontext __user *sc, long *pr0)
		       struct sigcontext __user *sc)
{
	int err = 0;
	int i;
@@ -75,17 +75,15 @@ int restore_sigcontext(struct pt_regs *regs,

	regs->faultnum = INT_SWINT_1_SIGRETURN;

	err |= __get_user(*pr0, &sc->gregs[0]);
	return err;
}

/* sigreturn() returns long since it restores r0 in the interrupted code. */
/* The assembly shim for this function arranges to ignore the return value. */
SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
{
	struct rt_sigframe __user *frame =
		(struct rt_sigframe __user *)(regs->sp);
	sigset_t set;
	long r0;

	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
		goto badframe;
@@ -98,13 +96,13 @@ SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);

	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
		goto badframe;

	if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
		goto badframe;

	return r0;
	return 0;

badframe:
	force_sig(SIGSEGV, current);