Generic way to track the land vma area.
As a bonus, after unmapping sigpage, kernel won't try to land on its
previous position.

Signed-off-by: Dmitry Safonov <d...@arista.com>
---
 arch/arm64/Kconfig           |  1 +
 arch/arm64/kernel/signal32.c | 17 ++++++++++++-----
 arch/arm64/kernel/vdso.c     |  2 +-
 3 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 7111cf335ede..56505e396253 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -38,6 +38,7 @@ config ARM64
        select ARCH_HAS_SYSCALL_WRAPPER
        select ARCH_HAS_TEARDOWN_DMA_OPS if IOMMU_SUPPORT
        select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
+       select ARCH_HAS_USER_LANDING
        select ARCH_HAVE_ELF_PROT
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select ARCH_INLINE_READ_LOCK if !PREEMPTION
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 2f507f565c48..61d583c73be3 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -315,7 +315,7 @@ static void __user *compat_get_sigframe(struct ksignal 
*ksig,
        return frame;
 }
 
-static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
+static int compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
                                compat_ulong_t __user *rc, void __user *frame,
                                int usig)
 {
@@ -342,13 +342,16 @@ static void compat_setup_return(struct pt_regs *regs, 
struct k_sigaction *ka,
                retcode = ptr_to_compat(ka->sa.sa_restorer);
        } else {
                /* Set up sigreturn pointer */
+               unsigned long land = (unsigned long)current->mm->user_landing;
                unsigned int idx = thumb << 1;
 
                if (ka->sa.sa_flags & SA_SIGINFO)
                        idx += 3;
 
-               retcode = (unsigned long)current->mm->context.sigpage +
-                         (idx << 2) + thumb;
+               if (land == UNMAPPED_USER_LANDING)
+                       return 1;
+
+               retcode = land + (idx << 2) + thumb;
        }
 
        regs->regs[0]   = usig;
@@ -356,6 +359,8 @@ static void compat_setup_return(struct pt_regs *regs, 
struct k_sigaction *ka,
        regs->compat_lr = retcode;
        regs->pc        = handler;
        regs->pstate    = spsr;
+
+       return 0;
 }
 
 static int compat_setup_sigframe(struct compat_sigframe __user *sf,
@@ -425,7 +430,8 @@ int compat_setup_rt_frame(int usig, struct ksignal *ksig,
        err |= compat_setup_sigframe(&frame->sig, regs, set);
 
        if (err == 0) {
-               compat_setup_return(regs, &ksig->ka, frame->sig.retcode, frame, 
usig);
+               err = compat_setup_return(regs, &ksig->ka,
+                                         frame->sig.retcode, frame, usig);
                regs->regs[1] = (compat_ulong_t)(unsigned long)&frame->info;
                regs->regs[2] = (compat_ulong_t)(unsigned long)&frame->sig.uc;
        }
@@ -448,7 +454,8 @@ int compat_setup_frame(int usig, struct ksignal *ksig, 
sigset_t *set,
 
        err |= compat_setup_sigframe(frame, regs, set);
        if (err == 0)
-               compat_setup_return(regs, &ksig->ka, frame->retcode, frame, 
usig);
+               err = compat_setup_return(regs, &ksig->ka,
+                                         frame->retcode, frame, usig);
 
        return err;
 }
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 91c1b7c716b7..08e8f1d56d92 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -394,7 +394,7 @@ static int aarch32_sigreturn_setup(struct mm_struct *mm)
        if (IS_ERR(ret))
                goto out;
 
-       mm->context.sigpage = (void *)addr;
+       mm->user_landing = (void __user *)addr;
 
 out:
        return PTR_ERR_OR_ZERO(ret);
-- 
2.28.0

Reply via email to