Generic way to track the landing vma area. As a bonus, after unmapping sigpage, kernel won't try to land on its previous position (due to UNMAPPED_VDSO_BASE check instead of context.vdso ?= 0 check).
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 35d8e4acd38d..a93ec99644b8 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_VDSO_BASE 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..3d2ac8062e99 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->vdso_base; 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_VDSO_BASE) + 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..03a6519d50cd 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->vdso_base = (void __user *)addr; out: return PTR_ERR_OR_ZERO(ret); -- 2.29.2