diff options
| -rw-r--r-- | arch/x86/kernel/signal.c | 48 |
1 files changed, 27 insertions, 21 deletions
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index d2cc6428c587..dfcc74ab0ab6 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
| @@ -211,31 +211,27 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, | |||
| 211 | { | 211 | { |
| 212 | /* Default to using normal stack */ | 212 | /* Default to using normal stack */ |
| 213 | unsigned long sp = regs->sp; | 213 | unsigned long sp = regs->sp; |
| 214 | int onsigstack = on_sig_stack(sp); | ||
| 214 | 215 | ||
| 215 | #ifdef CONFIG_X86_64 | 216 | #ifdef CONFIG_X86_64 |
| 216 | /* redzone */ | 217 | /* redzone */ |
| 217 | sp -= 128; | 218 | sp -= 128; |
| 218 | #endif /* CONFIG_X86_64 */ | 219 | #endif /* CONFIG_X86_64 */ |
| 219 | 220 | ||
| 220 | /* | 221 | if (!onsigstack) { |
| 221 | * If we are on the alternate signal stack and would overflow it, don't. | 222 | /* This is the X/Open sanctioned signal stack switching. */ |
| 222 | * Return an always-bogus address instead so we will die with SIGSEGV. | 223 | if (ka->sa.sa_flags & SA_ONSTACK) { |
| 223 | */ | 224 | if (sas_ss_flags(sp) == 0) |
| 224 | if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) | 225 | sp = current->sas_ss_sp + current->sas_ss_size; |
| 225 | return (void __user *) -1L; | 226 | } else { |
| 226 | |||
| 227 | /* This is the X/Open sanctioned signal stack switching. */ | ||
| 228 | if (ka->sa.sa_flags & SA_ONSTACK) { | ||
| 229 | if (sas_ss_flags(sp) == 0) | ||
| 230 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
| 231 | } else { | ||
| 232 | #ifdef CONFIG_X86_32 | 227 | #ifdef CONFIG_X86_32 |
| 233 | /* This is the legacy signal stack switching. */ | 228 | /* This is the legacy signal stack switching. */ |
| 234 | if ((regs->ss & 0xffff) != __USER_DS && | 229 | if ((regs->ss & 0xffff) != __USER_DS && |
| 235 | !(ka->sa.sa_flags & SA_RESTORER) && | 230 | !(ka->sa.sa_flags & SA_RESTORER) && |
| 236 | ka->sa.sa_restorer) | 231 | ka->sa.sa_restorer) |
| 237 | sp = (unsigned long) ka->sa.sa_restorer; | 232 | sp = (unsigned long) ka->sa.sa_restorer; |
| 238 | #endif /* CONFIG_X86_32 */ | 233 | #endif /* CONFIG_X86_32 */ |
| 234 | } | ||
| 239 | } | 235 | } |
| 240 | 236 | ||
| 241 | if (used_math()) { | 237 | if (used_math()) { |
| @@ -244,12 +240,22 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, | |||
| 244 | sp = round_down(sp, 64); | 240 | sp = round_down(sp, 64); |
| 245 | #endif /* CONFIG_X86_64 */ | 241 | #endif /* CONFIG_X86_64 */ |
| 246 | *fpstate = (void __user *)sp; | 242 | *fpstate = (void __user *)sp; |
| 247 | |||
| 248 | if (save_i387_xstate(*fpstate) < 0) | ||
| 249 | return (void __user *)-1L; | ||
| 250 | } | 243 | } |
| 251 | 244 | ||
| 252 | return (void __user *)align_sigframe(sp - frame_size); | 245 | sp = align_sigframe(sp - frame_size); |
| 246 | |||
| 247 | /* | ||
| 248 | * If we are on the alternate signal stack and would overflow it, don't. | ||
| 249 | * Return an always-bogus address instead so we will die with SIGSEGV. | ||
| 250 | */ | ||
| 251 | if (onsigstack && !likely(on_sig_stack(sp))) | ||
| 252 | return (void __user *)-1L; | ||
| 253 | |||
| 254 | /* save i387 state */ | ||
| 255 | if (used_math() && save_i387_xstate(*fpstate) < 0) | ||
| 256 | return (void __user *)-1L; | ||
| 257 | |||
| 258 | return (void __user *)sp; | ||
| 253 | } | 259 | } |
| 254 | 260 | ||
| 255 | #ifdef CONFIG_X86_32 | 261 | #ifdef CONFIG_X86_32 |
