Commit 9c2cc74f authored by Max Filippov's avatar Max Filippov
Browse files

xtensa: fix signal delivery to FDPIC process



Fetch function descriptor pointed to by the signal handler pointer from
userspace on signal delivery and function pointer pointed to by the
sa_restorer on return from the signal handler.

Cc: stable@vger.kernel.org
Fixes: e3ddb8bb ("xtensa: add FDPIC and static PIE support for noMMU")
Signed-off-by: default avatarMax Filippov <jcmvbkbc@gmail.com>
parent 457391b0
Loading
Loading
Loading
Loading
+27 −8
Original line number Diff line number Diff line
@@ -343,7 +343,19 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set,
	struct rt_sigframe *frame;
	int err = 0, sig = ksig->sig;
	unsigned long sp, ra, tp, ps;
	unsigned long handler = (unsigned long)ksig->ka.sa.sa_handler;
	unsigned long handler_fdpic_GOT = 0;
	unsigned int base;
	bool fdpic = IS_ENABLED(CONFIG_BINFMT_ELF_FDPIC) &&
		(current->personality & FDPIC_FUNCPTRS);

	if (fdpic) {
		unsigned long __user *fdpic_func_desc =
			(unsigned long __user *)handler;
		if (__get_user(handler, &fdpic_func_desc[0]) ||
		    __get_user(handler_fdpic_GOT, &fdpic_func_desc[1]))
			return -EFAULT;
	}

	sp = regs->areg[1];

@@ -373,19 +385,25 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set,
	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));

	if (ksig->ka.sa.sa_flags & SA_RESTORER) {
		if (fdpic) {
			unsigned long __user *fdpic_func_desc =
				(unsigned long __user *)ksig->ka.sa.sa_restorer;

			err |= __get_user(ra, fdpic_func_desc);
		} else {
			ra = (unsigned long)ksig->ka.sa.sa_restorer;
		}
	} else {

		/* Create sys_rt_sigreturn syscall in stack frame */

		err |= gen_return_code(frame->retcode);

		if (err) {
			return -EFAULT;
		}
		ra = (unsigned long) frame->retcode;
	}

	if (err)
		return -EFAULT;

	/*
	 * Create signal handler execution context.
	 * Return context not modified until this point.
@@ -394,8 +412,7 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set,
	/* Set up registers for signal handler; preserve the threadptr */
	tp = regs->threadptr;
	ps = regs->ps;
	start_thread(regs, (unsigned long) ksig->ka.sa.sa_handler,
		     (unsigned long) frame);
	start_thread(regs, handler, (unsigned long)frame);

	/* Set up a stack frame for a call4 if userspace uses windowed ABI */
	if (ps & PS_WOE_MASK) {
@@ -413,6 +430,8 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set,
	regs->areg[base + 4] = (unsigned long) &frame->uc;
	regs->threadptr = tp;
	regs->ps = ps;
	if (fdpic)
		regs->areg[base + 11] = handler_fdpic_GOT;

	pr_debug("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08lx\n",
		 current->comm, current->pid, sig, frame, regs->pc);