diff options
author | Brian Gerst <brgerst@gmail.com> | 2022-06-06 23:37:59 +0300 |
---|---|---|
committer | Borislav Petkov <bp@suse.de> | 2022-10-19 10:58:49 +0300 |
commit | 9c36e592b3f899c90b9d0d46ae29fcc065051b96 (patch) | |
tree | e7760700e98eace8b537cfa3a3bccf07981fbe24 /arch/x86/kernel | |
parent | 695c39bc5b8686a6b27254e60fb830f4989f322d (diff) | |
download | linux-9c36e592b3f899c90b9d0d46ae29fcc065051b96.tar.xz |
x86/signal: Merge get_sigframe()
Adapt the native get_sigframe() function so that the compat signal code
can use it.
Signed-off-by: Brian Gerst <brgerst@gmail.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Link: https://lore.kernel.org/r/20220606203802.158958-6-brgerst@gmail.com
Signed-off-by: Borislav Petkov <bp@suse.de>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r-- | arch/x86/kernel/signal.c | 80 |
1 files changed, 38 insertions, 42 deletions
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 489a0859afd2..890ca0523570 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -48,6 +48,23 @@ #include <asm/sigframe.h> #include <asm/signal.h> +static inline int is_ia32_compat_frame(struct ksignal *ksig) +{ + return IS_ENABLED(CONFIG_IA32_EMULATION) && + ksig->ka.sa.sa_flags & SA_IA32_ABI; +} + +static inline int is_ia32_frame(struct ksignal *ksig) +{ + return IS_ENABLED(CONFIG_X86_32) || is_ia32_compat_frame(ksig); +} + +static inline int is_x32_frame(struct ksignal *ksig) +{ + return IS_ENABLED(CONFIG_X86_X32_ABI) && + ksig->ka.sa.sa_flags & SA_X32_ABI; +} + #ifdef CONFIG_X86_64 /* * If regs->ss will cause an IRET fault, change it. Otherwise leave it @@ -223,24 +240,12 @@ do { \ /* * Determine which stack to use.. */ -static unsigned long align_sigframe(unsigned long sp) -{ -#ifdef CONFIG_X86_32 - /* - * Align the stack pointer according to the i386 ABI, - * i.e. so that on function entry ((sp + 4) & 15) == 0. - */ - sp = ((sp + 4) & -FRAME_ALIGNMENT) - 4; -#else /* !CONFIG_X86_32 */ - sp = round_down(sp, FRAME_ALIGNMENT) - 8; -#endif - return sp; -} - -static void __user * -get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, +void __user * +get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size, void __user **fpstate) { + struct k_sigaction *ka = &ksig->ka; + int ia32_frame = is_ia32_frame(ksig); /* Default to using normal stack */ bool nested_altstack = on_sig_stack(regs->sp); bool entering_altstack = false; @@ -249,7 +254,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, unsigned long buf_fx = 0; /* redzone */ - if (IS_ENABLED(CONFIG_X86_64)) + if (!ia32_frame) sp -= 128; /* This is the X/Open sanctioned signal stack switching. */ @@ -263,7 +268,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, sp = current->sas_ss_sp + current->sas_ss_size; entering_altstack = true; } - } else if (IS_ENABLED(CONFIG_X86_32) && + } else if (ia32_frame && !nested_altstack && regs->ss != __USER_DS && !(ka->sa.sa_flags & SA_RESTORER) && @@ -273,11 +278,19 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, entering_altstack = true; } - sp = fpu__alloc_mathframe(sp, IS_ENABLED(CONFIG_X86_32), - &buf_fx, &math_size); + sp = fpu__alloc_mathframe(sp, ia32_frame, &buf_fx, &math_size); *fpstate = (void __user *)sp; - sp = align_sigframe(sp - frame_size); + sp -= frame_size; + + if (ia32_frame) + /* + * Align the stack pointer according to the i386 ABI, + * i.e. so that on function entry ((sp + 4) & 15) == 0. + */ + sp = ((sp + 4) & -FRAME_ALIGNMENT) - 4; + else + sp = round_down(sp, FRAME_ALIGNMENT) - 8; /* * If we are on the alternate signal stack and would overflow it, don't. @@ -331,7 +344,7 @@ __setup_frame(struct ksignal *ksig, struct pt_regs *regs) void __user *restorer; void __user *fp = NULL; - frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fp); + frame = get_sigframe(ksig, regs, sizeof(*frame), &fp); if (!user_access_begin(frame, sizeof(*frame))) return -EFAULT; @@ -386,7 +399,7 @@ static int __setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) void __user *restorer; void __user *fp = NULL; - frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fp); + frame = get_sigframe(ksig, regs, sizeof(*frame), &fp); if (!user_access_begin(frame, sizeof(*frame))) return -EFAULT; @@ -469,7 +482,7 @@ static int __setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) if (!(ksig->ka.sa.sa_flags & SA_RESTORER)) return -EFAULT; - frame = get_sigframe(&ksig->ka, regs, sizeof(struct rt_sigframe), &fp); + frame = get_sigframe(ksig, regs, sizeof(struct rt_sigframe), &fp); uc_flags = frame_uc_flags(regs); if (!user_access_begin(frame, sizeof(*frame))) @@ -572,7 +585,7 @@ static int x32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) if (!(ksig->ka.sa.sa_flags & SA_RESTORER)) return -EFAULT; - frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fp); + frame = get_sigframe(ksig, regs, sizeof(*frame), &fp); uc_flags = frame_uc_flags(regs); @@ -742,23 +755,6 @@ unsigned long get_sigframe_size(void) return max_frame_size; } -static inline int is_ia32_compat_frame(struct ksignal *ksig) -{ - return IS_ENABLED(CONFIG_IA32_EMULATION) && - ksig->ka.sa.sa_flags & SA_IA32_ABI; -} - -static inline int is_ia32_frame(struct ksignal *ksig) -{ - return IS_ENABLED(CONFIG_X86_32) || is_ia32_compat_frame(ksig); -} - -static inline int is_x32_frame(struct ksignal *ksig) -{ - return IS_ENABLED(CONFIG_X86_X32_ABI) && - ksig->ka.sa.sa_flags & SA_X32_ABI; -} - static int setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs) { |