diff options
Diffstat (limited to 'arch/x86/kernel/signal_32.c')
-rw-r--r-- | arch/x86/kernel/signal_32.c | 45 |
1 files changed, 21 insertions, 24 deletions
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index 2a2435d3037d..b21070ea33a4 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c | |||
@@ -161,28 +161,14 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
161 | } | 161 | } |
162 | 162 | ||
163 | { | 163 | { |
164 | struct _fpstate __user *buf; | 164 | void __user *buf; |
165 | 165 | ||
166 | err |= __get_user(buf, &sc->fpstate); | 166 | err |= __get_user(buf, &sc->fpstate); |
167 | if (buf) { | 167 | err |= restore_i387_xstate(buf); |
168 | if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) | ||
169 | goto badframe; | ||
170 | err |= restore_i387(buf); | ||
171 | } else { | ||
172 | struct task_struct *me = current; | ||
173 | |||
174 | if (used_math()) { | ||
175 | clear_fpu(me); | ||
176 | clear_used_math(); | ||
177 | } | ||
178 | } | ||
179 | } | 168 | } |
180 | 169 | ||
181 | err |= __get_user(*pax, &sc->ax); | 170 | err |= __get_user(*pax, &sc->ax); |
182 | return err; | 171 | return err; |
183 | |||
184 | badframe: | ||
185 | return 1; | ||
186 | } | 172 | } |
187 | 173 | ||
188 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) | 174 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) |
@@ -264,7 +250,7 @@ badframe: | |||
264 | * Set up a signal frame. | 250 | * Set up a signal frame. |
265 | */ | 251 | */ |
266 | static int | 252 | static int |
267 | setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, | 253 | setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, |
268 | struct pt_regs *regs, unsigned long mask) | 254 | struct pt_regs *regs, unsigned long mask) |
269 | { | 255 | { |
270 | int tmp, err = 0; | 256 | int tmp, err = 0; |
@@ -291,7 +277,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, | |||
291 | err |= __put_user(regs->sp, &sc->sp_at_signal); | 277 | err |= __put_user(regs->sp, &sc->sp_at_signal); |
292 | err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); | 278 | err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss); |
293 | 279 | ||
294 | tmp = save_i387(fpstate); | 280 | tmp = save_i387_xstate(fpstate); |
295 | if (tmp < 0) | 281 | if (tmp < 0) |
296 | err = 1; | 282 | err = 1; |
297 | else | 283 | else |
@@ -308,7 +294,8 @@ setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate, | |||
308 | * Determine which stack to use.. | 294 | * Determine which stack to use.. |
309 | */ | 295 | */ |
310 | static inline void __user * | 296 | static inline void __user * |
311 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | 297 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, |
298 | void **fpstate) | ||
312 | { | 299 | { |
313 | unsigned long sp; | 300 | unsigned long sp; |
314 | 301 | ||
@@ -334,6 +321,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | |||
334 | sp = (unsigned long) ka->sa.sa_restorer; | 321 | sp = (unsigned long) ka->sa.sa_restorer; |
335 | } | 322 | } |
336 | 323 | ||
324 | if (used_math()) { | ||
325 | sp = sp - sig_xstate_size; | ||
326 | *fpstate = (struct _fpstate *) sp; | ||
327 | } | ||
328 | |||
337 | sp -= frame_size; | 329 | sp -= frame_size; |
338 | /* | 330 | /* |
339 | * Align the stack pointer according to the i386 ABI, | 331 | * Align the stack pointer according to the i386 ABI, |
@@ -352,8 +344,9 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
352 | void __user *restorer; | 344 | void __user *restorer; |
353 | int err = 0; | 345 | int err = 0; |
354 | int usig; | 346 | int usig; |
347 | void __user *fpstate = NULL; | ||
355 | 348 | ||
356 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 349 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
357 | 350 | ||
358 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 351 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
359 | goto give_sigsegv; | 352 | goto give_sigsegv; |
@@ -368,7 +361,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
368 | if (err) | 361 | if (err) |
369 | goto give_sigsegv; | 362 | goto give_sigsegv; |
370 | 363 | ||
371 | err = setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]); | 364 | err = setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]); |
372 | if (err) | 365 | if (err) |
373 | goto give_sigsegv; | 366 | goto give_sigsegv; |
374 | 367 | ||
@@ -429,8 +422,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
429 | void __user *restorer; | 422 | void __user *restorer; |
430 | int err = 0; | 423 | int err = 0; |
431 | int usig; | 424 | int usig; |
425 | void __user *fpstate = NULL; | ||
432 | 426 | ||
433 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 427 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
434 | 428 | ||
435 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 429 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
436 | goto give_sigsegv; | 430 | goto give_sigsegv; |
@@ -449,13 +443,16 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
449 | goto give_sigsegv; | 443 | goto give_sigsegv; |
450 | 444 | ||
451 | /* Create the ucontext. */ | 445 | /* Create the ucontext. */ |
452 | err |= __put_user(0, &frame->uc.uc_flags); | 446 | if (cpu_has_xsave) |
447 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
448 | else | ||
449 | err |= __put_user(0, &frame->uc.uc_flags); | ||
453 | err |= __put_user(0, &frame->uc.uc_link); | 450 | err |= __put_user(0, &frame->uc.uc_link); |
454 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 451 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
455 | err |= __put_user(sas_ss_flags(regs->sp), | 452 | err |= __put_user(sas_ss_flags(regs->sp), |
456 | &frame->uc.uc_stack.ss_flags); | 453 | &frame->uc.uc_stack.ss_flags); |
457 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 454 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
458 | err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, | 455 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, |
459 | regs, set->sig[0]); | 456 | regs, set->sig[0]); |
460 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 457 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
461 | if (err) | 458 | if (err) |