From: Yury Norov ynorov@caviumnetworks.com
hulk inclusion category: feature bugzilla: NA CVE: NA ---------------------------
ILP32 uses AARCH32 compat structures and syscall handlers for signals. But ILP32 rt_sigframe and ucontext structures differ from both LP64 and AARCH32.
From software point of view ILP32 is typical 32-bit compat ABI, and from
hardware point of view, it's just like LP64.
struct rt_sigframe defined in this patch in arch/arm64/kernel/signal_ilp32.c redefines one in arch/arm64/kernel/signal.c. And functions located in arch/arm64/include/signal_common.h pick up new structure to generate the code suitable for ILP32.
Signed-off-by: Yury Norov ynorov@caviumnetworks.com
Conflicts: arch/arm64/kernel/signal.c [wangxiongfeng: fix small conflict because of we include 'asm/ras.h' in arch/arm64/kernel/signal.c ] Signed-off-by: Xiongfeng Wang wangxiongfeng2@huawei.com Reviewed-by: Hanjun Guo <guohanjun@huawei.com mailto:guohanjun@huawei.com> Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- arch/arm64/include/asm/signal_ilp32.h | 23 +++++++++ arch/arm64/kernel/Makefile | 3 +- arch/arm64/kernel/signal.c | 3 ++ arch/arm64/kernel/signal_ilp32.c | 67 +++++++++++++++++++++++++++ arch/arm64/kernel/sys_ilp32.c | 6 +++ 5 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/include/asm/signal_ilp32.h create mode 100644 arch/arm64/kernel/signal_ilp32.c
diff --git a/arch/arm64/include/asm/signal_ilp32.h b/arch/arm64/include/asm/signal_ilp32.h new file mode 100644 index 0000000000000..7ee97c1336056 --- /dev/null +++ b/arch/arm64/include/asm/signal_ilp32.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef __ASM_SIGNAL_ILP32_H +#define __ASM_SIGNAL_ILP32_H + +#ifdef CONFIG_ARM64_ILP32 + +#include <linux/compat.h> + +int ilp32_setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set, + struct pt_regs *regs); + +#else + +static inline int ilp32_setup_rt_frame(int usig, struct ksignal *ksig, + sigset_t *set, struct pt_regs *regs) +{ + return -ENOSYS; +} + +#endif /* CONFIG_ARM64_ILP32 */ + +#endif /* __ASM_SIGNAL_ILP32_H */ diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 5265332bc35a4..8c9aa732ed037 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -29,7 +29,8 @@ $(obj)/%.stub.o: $(obj)/%.o FORCE
arm64-obj-$(CONFIG_AARCH32_EL0) += sys32.o kuser32.o signal32.o \ sys_compat.o binfmt_elf32.o -arm64-obj-$(CONFIG_ARM64_ILP32) += binfmt_ilp32.o sys_ilp32.o +arm64-obj-$(CONFIG_ARM64_ILP32) += binfmt_ilp32.o sys_ilp32.o \ + signal_ilp32.o arm64-obj-$(CONFIG_COMPAT) += sys32_common.o signal32_common.o arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index fc2521511cd0e..a733bbb709a68 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -44,6 +44,7 @@ #include <asm/traps.h> #include <asm/vdso.h> #include <asm/ras.h> +#include <asm/signal_ilp32.h>
#define get_sigset(s, m) __copy_from_user(s, m, sizeof(*s)) #define put_sigset(s, m) __copy_to_user(m, s, sizeof(*s)) @@ -586,6 +587,8 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) ret = a32_setup_rt_frame(usig, ksig, oldset, regs); else ret = a32_setup_frame(usig, ksig, oldset, regs); + } else if (is_ilp32_compat_task()) { + ret = ilp32_setup_rt_frame(usig, ksig, oldset, regs); } else { ret = setup_rt_frame(usig, ksig, oldset, regs); } diff --git a/arch/arm64/kernel/signal_ilp32.c b/arch/arm64/kernel/signal_ilp32.c new file mode 100644 index 0000000000000..6e84c8669a608 --- /dev/null +++ b/arch/arm64/kernel/signal_ilp32.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Copyright (C) 1995-2009 Russell King + * Copyright (C) 2012 ARM Ltd. + * Copyright (C) 2018 Cavium Networks. + * Yury Norov ynorov@caviumnetworks.com + */ + +#include <linux/compat.h> +#include <linux/signal.h> +#include <linux/syscalls.h> + +#include <asm/fpsimd.h> +#include <asm/unistd.h> +#include <asm/ucontext.h> +#include <asm/vdso.h> + +#include <asm/signal_ilp32.h> +#include <asm/signal32_common.h> + +#define get_sigset(s, m) get_sigset_t(s, m) +#define put_sigset(s, m) put_sigset_t(m, s) + +#define restore_altstack(stack) compat_restore_altstack(stack) +#define __save_altstack(stack, sp) __compat_save_altstack(stack, sp) +#define copy_siginfo_to_user(frame_info, ksig_info) \ + copy_siginfo_to_user32(frame_info, ksig_info) + +#define setup_return(regs, ka, user_layout, usig) \ +{ \ + __setup_return(regs, ka, user_layout, usig); \ + regs->regs[30] = \ + (unsigned long)VDSO_SYMBOL(current->mm->context.vdso, \ + sigtramp_ilp32); \ +} + +struct ilp32_ucontext { + u32 uc_flags; + u32 uc_link; + compat_stack_t uc_stack; + compat_sigset_t uc_sigmask; + /* glibc uses a 1024-bit sigset_t */ + __u8 __unused[1024 / 8 - sizeof(compat_sigset_t)]; + /* last for future expansion */ + struct sigcontext uc_mcontext; +}; + +struct rt_sigframe { + struct compat_siginfo info; + struct ilp32_ucontext uc; +}; + +#include <asm/signal_common.h> + +COMPAT_SYSCALL_DEFINE0(ilp32_rt_sigreturn) +{ + struct pt_regs *regs = current_pt_regs(); + + return __sys_rt_sigreturn(regs); +} + +int ilp32_setup_rt_frame(int usig, struct ksignal *ksig, + sigset_t *set, struct pt_regs *regs) +{ + return __setup_rt_frame(usig, ksig, set, regs); +} diff --git a/arch/arm64/kernel/sys_ilp32.c b/arch/arm64/kernel/sys_ilp32.c index 169a381363110..ce82c297da3b7 100644 --- a/arch/arm64/kernel/sys_ilp32.c +++ b/arch/arm64/kernel/sys_ilp32.c @@ -48,6 +48,12 @@ #define __arm64_compat_sys_fstatfs64 __arm64_compat_sys_aarch32_fstatfs64 #define __arm64_compat_sys_statfs64 __arm64_compat_sys_aarch32_statfs64
+/* + * Using custom wrapper for rt_sigreturn() to handle custom + * struct rt_sigframe. + */ +#define __arm64_compat_sys_rt_sigreturn __arm64_compat_sys_ilp32_rt_sigreturn + /* * Wrappers to pass the pt_regs argument. */