[PATCH v2 17/19] arm64/vdso: Migrate compat signals to generic vdso_base

Dmitry Safonov
2020-11-24T00:30:29Z

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 <dima@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