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 Suggested-by: Kevin Brodsky Suggested-by: kemal Signed-off-by: Jinjie Ruan --- 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