]> git.itanic.dy.fi Git - linux-stable/commitdiff
xtensa: fix signal delivery to FDPIC process
authorMax Filippov <jcmvbkbc@gmail.com>
Tue, 2 May 2023 10:20:47 +0000 (03:20 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 30 May 2023 13:17:22 +0000 (14:17 +0100)
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: e3ddb8bbe0f8 ("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>
arch/xtensa/kernel/signal.c

index 876d5df157ed986ff3d919aba15fca177806d56e..5c01d7e70d90da4a0f495273180005cf235f4a7c 100644 (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);