diff options
Diffstat (limited to 'arch/x86/ia32/ia32_signal.c')
-rw-r--r-- | arch/x86/ia32/ia32_signal.c | 138 |
1 files changed, 60 insertions, 78 deletions
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 20af4c79579a..4bc02b23674b 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c | |||
@@ -179,9 +179,10 @@ struct sigframe | |||
179 | u32 pretcode; | 179 | u32 pretcode; |
180 | int sig; | 180 | int sig; |
181 | struct sigcontext_ia32 sc; | 181 | struct sigcontext_ia32 sc; |
182 | struct _fpstate_ia32 fpstate; | 182 | struct _fpstate_ia32 fpstate_unused; /* look at kernel/sigframe.h */ |
183 | unsigned int extramask[_COMPAT_NSIG_WORDS-1]; | 183 | unsigned int extramask[_COMPAT_NSIG_WORDS-1]; |
184 | char retcode[8]; | 184 | char retcode[8]; |
185 | /* fp state follows here */ | ||
185 | }; | 186 | }; |
186 | 187 | ||
187 | struct rt_sigframe | 188 | struct rt_sigframe |
@@ -192,8 +193,8 @@ struct rt_sigframe | |||
192 | u32 puc; | 193 | u32 puc; |
193 | compat_siginfo_t info; | 194 | compat_siginfo_t info; |
194 | struct ucontext_ia32 uc; | 195 | struct ucontext_ia32 uc; |
195 | struct _fpstate_ia32 fpstate; | ||
196 | char retcode[8]; | 196 | char retcode[8]; |
197 | /* fp state follows here */ | ||
197 | }; | 198 | }; |
198 | 199 | ||
199 | #define COPY(x) { \ | 200 | #define COPY(x) { \ |
@@ -206,7 +207,7 @@ struct rt_sigframe | |||
206 | { unsigned int cur; \ | 207 | { unsigned int cur; \ |
207 | unsigned short pre; \ | 208 | unsigned short pre; \ |
208 | err |= __get_user(pre, &sc->seg); \ | 209 | err |= __get_user(pre, &sc->seg); \ |
209 | asm volatile("movl %%" #seg ",%0" : "=r" (cur)); \ | 210 | savesegment(seg, cur); \ |
210 | pre |= mask; \ | 211 | pre |= mask; \ |
211 | if (pre != cur) loadsegment(seg, pre); } | 212 | if (pre != cur) loadsegment(seg, pre); } |
212 | 213 | ||
@@ -215,7 +216,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, | |||
215 | unsigned int *peax) | 216 | unsigned int *peax) |
216 | { | 217 | { |
217 | unsigned int tmpflags, gs, oldgs, err = 0; | 218 | unsigned int tmpflags, gs, oldgs, err = 0; |
218 | struct _fpstate_ia32 __user *buf; | 219 | void __user *buf; |
219 | u32 tmp; | 220 | u32 tmp; |
220 | 221 | ||
221 | /* Always make any pending restarted system calls return -EINTR */ | 222 | /* Always make any pending restarted system calls return -EINTR */ |
@@ -235,7 +236,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, | |||
235 | */ | 236 | */ |
236 | err |= __get_user(gs, &sc->gs); | 237 | err |= __get_user(gs, &sc->gs); |
237 | gs |= 3; | 238 | gs |= 3; |
238 | asm("movl %%gs,%0" : "=r" (oldgs)); | 239 | savesegment(gs, oldgs); |
239 | if (gs != oldgs) | 240 | if (gs != oldgs) |
240 | load_gs_index(gs); | 241 | load_gs_index(gs); |
241 | 242 | ||
@@ -259,26 +260,12 @@ static int ia32_restore_sigcontext(struct pt_regs *regs, | |||
259 | 260 | ||
260 | err |= __get_user(tmp, &sc->fpstate); | 261 | err |= __get_user(tmp, &sc->fpstate); |
261 | buf = compat_ptr(tmp); | 262 | buf = compat_ptr(tmp); |
262 | if (buf) { | 263 | err |= restore_i387_xstate_ia32(buf); |
263 | if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) | ||
264 | goto badframe; | ||
265 | err |= restore_i387_ia32(buf); | ||
266 | } else { | ||
267 | struct task_struct *me = current; | ||
268 | |||
269 | if (used_math()) { | ||
270 | clear_fpu(me); | ||
271 | clear_used_math(); | ||
272 | } | ||
273 | } | ||
274 | 264 | ||
275 | err |= __get_user(tmp, &sc->ax); | 265 | err |= __get_user(tmp, &sc->ax); |
276 | *peax = tmp; | 266 | *peax = tmp; |
277 | 267 | ||
278 | return err; | 268 | return err; |
279 | |||
280 | badframe: | ||
281 | return 1; | ||
282 | } | 269 | } |
283 | 270 | ||
284 | asmlinkage long sys32_sigreturn(struct pt_regs *regs) | 271 | asmlinkage long sys32_sigreturn(struct pt_regs *regs) |
@@ -350,46 +337,42 @@ badframe: | |||
350 | */ | 337 | */ |
351 | 338 | ||
352 | static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, | 339 | static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, |
353 | struct _fpstate_ia32 __user *fpstate, | 340 | void __user *fpstate, |
354 | struct pt_regs *regs, unsigned int mask) | 341 | struct pt_regs *regs, unsigned int mask) |
355 | { | 342 | { |
356 | int tmp, err = 0; | 343 | int tmp, err = 0; |
357 | 344 | ||
358 | tmp = 0; | 345 | savesegment(gs, tmp); |
359 | __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp)); | ||
360 | err |= __put_user(tmp, (unsigned int __user *)&sc->gs); | 346 | err |= __put_user(tmp, (unsigned int __user *)&sc->gs); |
361 | __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp)); | 347 | savesegment(fs, tmp); |
362 | err |= __put_user(tmp, (unsigned int __user *)&sc->fs); | 348 | err |= __put_user(tmp, (unsigned int __user *)&sc->fs); |
363 | __asm__("movl %%ds,%0" : "=r"(tmp): "0"(tmp)); | 349 | savesegment(ds, tmp); |
364 | err |= __put_user(tmp, (unsigned int __user *)&sc->ds); | 350 | err |= __put_user(tmp, (unsigned int __user *)&sc->ds); |
365 | __asm__("movl %%es,%0" : "=r"(tmp): "0"(tmp)); | 351 | savesegment(es, tmp); |
366 | err |= __put_user(tmp, (unsigned int __user *)&sc->es); | 352 | err |= __put_user(tmp, (unsigned int __user *)&sc->es); |
367 | 353 | ||
368 | err |= __put_user((u32)regs->di, &sc->di); | 354 | err |= __put_user(regs->di, &sc->di); |
369 | err |= __put_user((u32)regs->si, &sc->si); | 355 | err |= __put_user(regs->si, &sc->si); |
370 | err |= __put_user((u32)regs->bp, &sc->bp); | 356 | err |= __put_user(regs->bp, &sc->bp); |
371 | err |= __put_user((u32)regs->sp, &sc->sp); | 357 | err |= __put_user(regs->sp, &sc->sp); |
372 | err |= __put_user((u32)regs->bx, &sc->bx); | 358 | err |= __put_user(regs->bx, &sc->bx); |
373 | err |= __put_user((u32)regs->dx, &sc->dx); | 359 | err |= __put_user(regs->dx, &sc->dx); |
374 | err |= __put_user((u32)regs->cx, &sc->cx); | 360 | err |= __put_user(regs->cx, &sc->cx); |
375 | err |= __put_user((u32)regs->ax, &sc->ax); | 361 | err |= __put_user(regs->ax, &sc->ax); |
376 | err |= __put_user((u32)regs->cs, &sc->cs); | 362 | err |= __put_user(regs->cs, &sc->cs); |
377 | err |= __put_user((u32)regs->ss, &sc->ss); | 363 | err |= __put_user(regs->ss, &sc->ss); |
378 | err |= __put_user(current->thread.trap_no, &sc->trapno); | 364 | err |= __put_user(current->thread.trap_no, &sc->trapno); |
379 | err |= __put_user(current->thread.error_code, &sc->err); | 365 | err |= __put_user(current->thread.error_code, &sc->err); |
380 | err |= __put_user((u32)regs->ip, &sc->ip); | 366 | err |= __put_user(regs->ip, &sc->ip); |
381 | err |= __put_user((u32)regs->flags, &sc->flags); | 367 | err |= __put_user(regs->flags, &sc->flags); |
382 | err |= __put_user((u32)regs->sp, &sc->sp_at_signal); | 368 | err |= __put_user(regs->sp, &sc->sp_at_signal); |
383 | 369 | ||
384 | tmp = save_i387_ia32(fpstate); | 370 | tmp = save_i387_xstate_ia32(fpstate); |
385 | if (tmp < 0) | 371 | if (tmp < 0) |
386 | err = -EFAULT; | 372 | err = -EFAULT; |
387 | else { | 373 | else |
388 | clear_used_math(); | ||
389 | stts(); | ||
390 | err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL), | 374 | err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL), |
391 | &sc->fpstate); | 375 | &sc->fpstate); |
392 | } | ||
393 | 376 | ||
394 | /* non-iBCS2 extensions.. */ | 377 | /* non-iBCS2 extensions.. */ |
395 | err |= __put_user(mask, &sc->oldmask); | 378 | err |= __put_user(mask, &sc->oldmask); |
@@ -402,7 +385,8 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc, | |||
402 | * Determine which stack to use.. | 385 | * Determine which stack to use.. |
403 | */ | 386 | */ |
404 | static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | 387 | static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, |
405 | size_t frame_size) | 388 | size_t frame_size, |
389 | void **fpstate) | ||
406 | { | 390 | { |
407 | unsigned long sp; | 391 | unsigned long sp; |
408 | 392 | ||
@@ -421,6 +405,11 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
421 | ka->sa.sa_restorer) | 405 | ka->sa.sa_restorer) |
422 | sp = (unsigned long) ka->sa.sa_restorer; | 406 | sp = (unsigned long) ka->sa.sa_restorer; |
423 | 407 | ||
408 | if (used_math()) { | ||
409 | sp = sp - sig_xstate_ia32_size; | ||
410 | *fpstate = (struct _fpstate_ia32 *) sp; | ||
411 | } | ||
412 | |||
424 | sp -= frame_size; | 413 | sp -= frame_size; |
425 | /* Align the stack pointer according to the i386 ABI, | 414 | /* Align the stack pointer according to the i386 ABI, |
426 | * i.e. so that on function entry ((sp + 4) & 15) == 0. */ | 415 | * i.e. so that on function entry ((sp + 4) & 15) == 0. */ |
@@ -434,6 +423,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
434 | struct sigframe __user *frame; | 423 | struct sigframe __user *frame; |
435 | void __user *restorer; | 424 | void __user *restorer; |
436 | int err = 0; | 425 | int err = 0; |
426 | void __user *fpstate = NULL; | ||
437 | 427 | ||
438 | /* copy_to_user optimizes that into a single 8 byte store */ | 428 | /* copy_to_user optimizes that into a single 8 byte store */ |
439 | static const struct { | 429 | static const struct { |
@@ -448,25 +438,21 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
448 | 0, | 438 | 0, |
449 | }; | 439 | }; |
450 | 440 | ||
451 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 441 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
452 | 442 | ||
453 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 443 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
454 | goto give_sigsegv; | 444 | return -EFAULT; |
455 | 445 | ||
456 | err |= __put_user(sig, &frame->sig); | 446 | if (__put_user(sig, &frame->sig)) |
457 | if (err) | 447 | return -EFAULT; |
458 | goto give_sigsegv; | ||
459 | 448 | ||
460 | err |= ia32_setup_sigcontext(&frame->sc, &frame->fpstate, regs, | 449 | if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0])) |
461 | set->sig[0]); | 450 | return -EFAULT; |
462 | if (err) | ||
463 | goto give_sigsegv; | ||
464 | 451 | ||
465 | if (_COMPAT_NSIG_WORDS > 1) { | 452 | if (_COMPAT_NSIG_WORDS > 1) { |
466 | err |= __copy_to_user(frame->extramask, &set->sig[1], | 453 | if (__copy_to_user(frame->extramask, &set->sig[1], |
467 | sizeof(frame->extramask)); | 454 | sizeof(frame->extramask))) |
468 | if (err) | 455 | return -EFAULT; |
469 | goto give_sigsegv; | ||
470 | } | 456 | } |
471 | 457 | ||
472 | if (ka->sa.sa_flags & SA_RESTORER) { | 458 | if (ka->sa.sa_flags & SA_RESTORER) { |
@@ -487,7 +473,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
487 | */ | 473 | */ |
488 | err |= __copy_to_user(frame->retcode, &code, 8); | 474 | err |= __copy_to_user(frame->retcode, &code, 8); |
489 | if (err) | 475 | if (err) |
490 | goto give_sigsegv; | 476 | return -EFAULT; |
491 | 477 | ||
492 | /* Set up registers for signal handler */ | 478 | /* Set up registers for signal handler */ |
493 | regs->sp = (unsigned long) frame; | 479 | regs->sp = (unsigned long) frame; |
@@ -498,8 +484,8 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
498 | regs->dx = 0; | 484 | regs->dx = 0; |
499 | regs->cx = 0; | 485 | regs->cx = 0; |
500 | 486 | ||
501 | asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); | 487 | loadsegment(ds, __USER32_DS); |
502 | asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); | 488 | loadsegment(es, __USER32_DS); |
503 | 489 | ||
504 | regs->cs = __USER32_CS; | 490 | regs->cs = __USER32_CS; |
505 | regs->ss = __USER32_DS; | 491 | regs->ss = __USER32_DS; |
@@ -510,10 +496,6 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka, | |||
510 | #endif | 496 | #endif |
511 | 497 | ||
512 | return 0; | 498 | return 0; |
513 | |||
514 | give_sigsegv: | ||
515 | force_sigsegv(sig, current); | ||
516 | return -EFAULT; | ||
517 | } | 499 | } |
518 | 500 | ||
519 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 501 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
@@ -522,6 +504,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
522 | struct rt_sigframe __user *frame; | 504 | struct rt_sigframe __user *frame; |
523 | void __user *restorer; | 505 | void __user *restorer; |
524 | int err = 0; | 506 | int err = 0; |
507 | void __user *fpstate = NULL; | ||
525 | 508 | ||
526 | /* __copy_to_user optimizes that into a single 8 byte store */ | 509 | /* __copy_to_user optimizes that into a single 8 byte store */ |
527 | static const struct { | 510 | static const struct { |
@@ -537,30 +520,33 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
537 | 0, | 520 | 0, |
538 | }; | 521 | }; |
539 | 522 | ||
540 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 523 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); |
541 | 524 | ||
542 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 525 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
543 | goto give_sigsegv; | 526 | return -EFAULT; |
544 | 527 | ||
545 | err |= __put_user(sig, &frame->sig); | 528 | err |= __put_user(sig, &frame->sig); |
546 | err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo); | 529 | err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo); |
547 | err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc); | 530 | err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc); |
548 | err |= copy_siginfo_to_user32(&frame->info, info); | 531 | err |= copy_siginfo_to_user32(&frame->info, info); |
549 | if (err) | 532 | if (err) |
550 | goto give_sigsegv; | 533 | return -EFAULT; |
551 | 534 | ||
552 | /* Create the ucontext. */ | 535 | /* Create the ucontext. */ |
553 | err |= __put_user(0, &frame->uc.uc_flags); | 536 | if (cpu_has_xsave) |
537 | err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
538 | else | ||
539 | err |= __put_user(0, &frame->uc.uc_flags); | ||
554 | err |= __put_user(0, &frame->uc.uc_link); | 540 | err |= __put_user(0, &frame->uc.uc_link); |
555 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 541 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
556 | err |= __put_user(sas_ss_flags(regs->sp), | 542 | err |= __put_user(sas_ss_flags(regs->sp), |
557 | &frame->uc.uc_stack.ss_flags); | 543 | &frame->uc.uc_stack.ss_flags); |
558 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 544 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
559 | err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, | 545 | err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate, |
560 | regs, set->sig[0]); | 546 | regs, set->sig[0]); |
561 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 547 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
562 | if (err) | 548 | if (err) |
563 | goto give_sigsegv; | 549 | return -EFAULT; |
564 | 550 | ||
565 | if (ka->sa.sa_flags & SA_RESTORER) | 551 | if (ka->sa.sa_flags & SA_RESTORER) |
566 | restorer = ka->sa.sa_restorer; | 552 | restorer = ka->sa.sa_restorer; |
@@ -575,7 +561,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
575 | */ | 561 | */ |
576 | err |= __copy_to_user(frame->retcode, &code, 8); | 562 | err |= __copy_to_user(frame->retcode, &code, 8); |
577 | if (err) | 563 | if (err) |
578 | goto give_sigsegv; | 564 | return -EFAULT; |
579 | 565 | ||
580 | /* Set up registers for signal handler */ | 566 | /* Set up registers for signal handler */ |
581 | regs->sp = (unsigned long) frame; | 567 | regs->sp = (unsigned long) frame; |
@@ -591,8 +577,8 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
591 | regs->dx = (unsigned long) &frame->info; | 577 | regs->dx = (unsigned long) &frame->info; |
592 | regs->cx = (unsigned long) &frame->uc; | 578 | regs->cx = (unsigned long) &frame->uc; |
593 | 579 | ||
594 | asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); | 580 | loadsegment(ds, __USER32_DS); |
595 | asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); | 581 | loadsegment(es, __USER32_DS); |
596 | 582 | ||
597 | regs->cs = __USER32_CS; | 583 | regs->cs = __USER32_CS; |
598 | regs->ss = __USER32_DS; | 584 | regs->ss = __USER32_DS; |
@@ -603,8 +589,4 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
603 | #endif | 589 | #endif |
604 | 590 | ||
605 | return 0; | 591 | return 0; |
606 | |||
607 | give_sigsegv: | ||
608 | force_sigsegv(sig, current); | ||
609 | return -EFAULT; | ||
610 | } | 592 | } |