xtensa: fix signal delivery to FDPIC process

commit 9c2cc74fb31ec76b8b118c97041a6a154a3ff219 upstream.

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: e3ddb8bbe0 ("xtensa: add FDPIC and static PIE support for noMMU")
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Max Filippov 2023-05-02 03:20:47 -07:00 committed by Greg Kroah-Hartman
parent 0845660508
commit 522bbbfcb6

View File

@ -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,20 +385,26 @@ 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) {
ra = (unsigned long)ksig->ka.sa.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);