[PATCH v17 15/15] arm64: vdso: Expose sigreturn address on vdso to the kernel

From: Jinjie Ruan

Date: Tue Jul 21 2026 - 04:32:37 EST


Syscall User Dispatch (SUD) must not intercept the signal trampoline
code, otherwise returning from a signal with a locked selector may
cause infinite recursion into the signal handler.

Provide an arm64 implementation of arch_syscall_is_vdso_sigreturn()
to exclude these sigreturn syscalls from dispatch.

For native 64-bit tasks, check whether the current PC matches the 'svc #0'
instruction inside the vDSO sigreturn trampoline (defined in
arch/arm64/kernel/vdso/sigreturn.S as below).

SYM_CODE_START(__kernel_rt_sigreturn)
mov x8, #__NR_rt_sigreturn
svc #0
SYM_CODE_END(__kernel_rt_sigreturn)

For COMPAT tasks, verify that the instruction falls within the dedicated
'sigpage' range, since compat signal handlers use this architecture-
specific page (not the vDSO) for their return trampoline. This prevents
SUD from incorrectly dispatching syscalls issued during signal return.

Suggested-by: Thomas Weißschuh <thomas.weissschuh@xxxxxxxxxxxxx>
Suggested-by: Kevin Brodsky <kevin.brodsky@xxxxxxx>
Suggested-by: kemal <kmal@xxxxxxx>
Signed-off-by: Jinjie Ruan <ruanjinjie@xxxxxxxxxx>
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/elf.h | 1 +
arch/arm64/kernel/vdso.c | 16 ++++++++++++++++
arch/arm64/kernel/vdso/sigreturn.S | 1 +
arch/arm64/kernel/vdso/vdso.lds.S | 1 +
5 files changed, 20 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index aea686dce3d5..a41d2b593899 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -86,6 +86,7 @@ config ARM64
select ARCH_SUPPORTS_SCHED_SMT
select ARCH_SUPPORTS_SCHED_CLUSTER
select ARCH_SUPPORTS_SCHED_MC
+ select ARCH_SUPPORTS_SYSCALL_USER_DISPATCH
select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
select ARCH_WANT_COMPAT_IPC_PARSE_VERSION if COMPAT
select ARCH_WANT_DEFAULT_BPF_JIT
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index d2779d604c7b..a8b232c5c6d9 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -293,6 +293,7 @@ static inline int arch_check_elf(void *ehdr, bool has_interp,
return 0;
}

+extern bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs);
#endif /* !__ASSEMBLER__ */

#endif
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 592dd8668de4..37cdc7c72e15 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -343,3 +343,19 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)

return ret;
}
+
+bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs)
+{
+ unsigned long landing_pad;
+
+#ifdef CONFIG_COMPAT
+ if (is_compat_task()) {
+ unsigned long sigpage = (unsigned long)current->mm->context.sigpage;
+
+ return regs->pc >= sigpage && regs->pc < (sigpage + PAGE_SIZE);
+ }
+#endif
+ landing_pad = (unsigned long)VDSO_SYMBOL(current->mm->context.vdso, sigreturn_landing_pad);
+
+ return regs->pc == landing_pad;
+}
diff --git a/arch/arm64/kernel/vdso/sigreturn.S b/arch/arm64/kernel/vdso/sigreturn.S
index 0e18729abc3b..8d2d413ff45e 100644
--- a/arch/arm64/kernel/vdso/sigreturn.S
+++ b/arch/arm64/kernel/vdso/sigreturn.S
@@ -73,6 +73,7 @@ SYM_CODE_START(__kernel_rt_sigreturn)
mov x8, #__NR_rt_sigreturn
// PLEASE DO NOT MODIFY
svc #0
+ SYM_INNER_LABEL(__sigreturn_landing_pad, SYM_L_GLOBAL)
// PLEASE DO NOT MODIFY
// .cfi_endproc
SYM_CODE_END(__kernel_rt_sigreturn)
diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S
index 52314be29191..da61d6fc6fe9 100644
--- a/arch/arm64/kernel/vdso/vdso.lds.S
+++ b/arch/arm64/kernel/vdso/vdso.lds.S
@@ -112,3 +112,4 @@ VERSION
* Make the sigreturn code visible to the kernel.
*/
VDSO_sigtramp = __kernel_rt_sigreturn;
+VDSO_sigreturn_landing_pad = __sigreturn_landing_pad;
--
2.34.1