diff options
Diffstat (limited to 'arch/x86/kernel/signal.c')
-rw-r--r-- | arch/x86/kernel/signal.c | 231 |
1 files changed, 103 insertions, 128 deletions
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index b280908a376e..b33144c8b309 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
@@ -114,11 +114,12 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
114 | regs->orig_ax = -1; /* disable syscall checks */ | 114 | regs->orig_ax = -1; /* disable syscall checks */ |
115 | 115 | ||
116 | get_user_ex(buf, &sc->fpstate); | 116 | get_user_ex(buf, &sc->fpstate); |
117 | err |= restore_i387_xstate(buf); | ||
118 | 117 | ||
119 | get_user_ex(*pax, &sc->ax); | 118 | get_user_ex(*pax, &sc->ax); |
120 | } get_user_catch(err); | 119 | } get_user_catch(err); |
121 | 120 | ||
121 | err |= restore_xstate_sig(buf, config_enabled(CONFIG_X86_32)); | ||
122 | |||
122 | return err; | 123 | return err; |
123 | } | 124 | } |
124 | 125 | ||
@@ -206,35 +207,32 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, | |||
206 | void __user **fpstate) | 207 | void __user **fpstate) |
207 | { | 208 | { |
208 | /* Default to using normal stack */ | 209 | /* Default to using normal stack */ |
210 | unsigned long math_size = 0; | ||
209 | unsigned long sp = regs->sp; | 211 | unsigned long sp = regs->sp; |
212 | unsigned long buf_fx = 0; | ||
210 | int onsigstack = on_sig_stack(sp); | 213 | int onsigstack = on_sig_stack(sp); |
211 | 214 | ||
212 | #ifdef CONFIG_X86_64 | ||
213 | /* redzone */ | 215 | /* redzone */ |
214 | sp -= 128; | 216 | if (config_enabled(CONFIG_X86_64)) |
215 | #endif /* CONFIG_X86_64 */ | 217 | sp -= 128; |
216 | 218 | ||
217 | if (!onsigstack) { | 219 | if (!onsigstack) { |
218 | /* This is the X/Open sanctioned signal stack switching. */ | 220 | /* This is the X/Open sanctioned signal stack switching. */ |
219 | if (ka->sa.sa_flags & SA_ONSTACK) { | 221 | if (ka->sa.sa_flags & SA_ONSTACK) { |
220 | if (current->sas_ss_size) | 222 | if (current->sas_ss_size) |
221 | sp = current->sas_ss_sp + current->sas_ss_size; | 223 | sp = current->sas_ss_sp + current->sas_ss_size; |
222 | } else { | 224 | } else if (config_enabled(CONFIG_X86_32) && |
223 | #ifdef CONFIG_X86_32 | 225 | (regs->ss & 0xffff) != __USER_DS && |
224 | /* This is the legacy signal stack switching. */ | 226 | !(ka->sa.sa_flags & SA_RESTORER) && |
225 | if ((regs->ss & 0xffff) != __USER_DS && | 227 | ka->sa.sa_restorer) { |
226 | !(ka->sa.sa_flags & SA_RESTORER) && | 228 | /* This is the legacy signal stack switching. */ |
227 | ka->sa.sa_restorer) | ||
228 | sp = (unsigned long) ka->sa.sa_restorer; | 229 | sp = (unsigned long) ka->sa.sa_restorer; |
229 | #endif /* CONFIG_X86_32 */ | ||
230 | } | 230 | } |
231 | } | 231 | } |
232 | 232 | ||
233 | if (used_math()) { | 233 | if (used_math()) { |
234 | sp -= sig_xstate_size; | 234 | sp = alloc_mathframe(sp, config_enabled(CONFIG_X86_32), |
235 | #ifdef CONFIG_X86_64 | 235 | &buf_fx, &math_size); |
236 | sp = round_down(sp, 64); | ||
237 | #endif /* CONFIG_X86_64 */ | ||
238 | *fpstate = (void __user *)sp; | 236 | *fpstate = (void __user *)sp; |
239 | } | 237 | } |
240 | 238 | ||
@@ -247,8 +245,9 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, | |||
247 | if (onsigstack && !likely(on_sig_stack(sp))) | 245 | if (onsigstack && !likely(on_sig_stack(sp))) |
248 | return (void __user *)-1L; | 246 | return (void __user *)-1L; |
249 | 247 | ||
250 | /* save i387 state */ | 248 | /* save i387 and extended state */ |
251 | if (used_math() && save_i387_xstate(*fpstate) < 0) | 249 | if (used_math() && |
250 | save_xstate_sig(*fpstate, (void __user *)buf_fx, math_size) < 0) | ||
252 | return (void __user *)-1L; | 251 | return (void __user *)-1L; |
253 | 252 | ||
254 | return (void __user *)sp; | 253 | return (void __user *)sp; |
@@ -357,7 +356,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
357 | put_user_ex(sig, &frame->sig); | 356 | put_user_ex(sig, &frame->sig); |
358 | put_user_ex(&frame->info, &frame->pinfo); | 357 | put_user_ex(&frame->info, &frame->pinfo); |
359 | put_user_ex(&frame->uc, &frame->puc); | 358 | put_user_ex(&frame->uc, &frame->puc); |
360 | err |= copy_siginfo_to_user(&frame->info, info); | ||
361 | 359 | ||
362 | /* Create the ucontext. */ | 360 | /* Create the ucontext. */ |
363 | if (cpu_has_xsave) | 361 | if (cpu_has_xsave) |
@@ -369,9 +367,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
369 | put_user_ex(sas_ss_flags(regs->sp), | 367 | put_user_ex(sas_ss_flags(regs->sp), |
370 | &frame->uc.uc_stack.ss_flags); | 368 | &frame->uc.uc_stack.ss_flags); |
371 | put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 369 | put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
372 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, | ||
373 | regs, set->sig[0]); | ||
374 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
375 | 370 | ||
376 | /* Set up to return from userspace. */ | 371 | /* Set up to return from userspace. */ |
377 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); | 372 | restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); |
@@ -388,6 +383,11 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
388 | */ | 383 | */ |
389 | put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode); | 384 | put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode); |
390 | } put_user_catch(err); | 385 | } put_user_catch(err); |
386 | |||
387 | err |= copy_siginfo_to_user(&frame->info, info); | ||
388 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, | ||
389 | regs, set->sig[0]); | ||
390 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
391 | 391 | ||
392 | if (err) | 392 | if (err) |
393 | return -EFAULT; | 393 | return -EFAULT; |
@@ -436,8 +436,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
436 | put_user_ex(sas_ss_flags(regs->sp), | 436 | put_user_ex(sas_ss_flags(regs->sp), |
437 | &frame->uc.uc_stack.ss_flags); | 437 | &frame->uc.uc_stack.ss_flags); |
438 | put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size); | 438 | put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size); |
439 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); | ||
440 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
441 | 439 | ||
442 | /* Set up to return from userspace. If provided, use a stub | 440 | /* Set up to return from userspace. If provided, use a stub |
443 | already in userspace. */ | 441 | already in userspace. */ |
@@ -450,6 +448,9 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
450 | } | 448 | } |
451 | } put_user_catch(err); | 449 | } put_user_catch(err); |
452 | 450 | ||
451 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); | ||
452 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
453 | |||
453 | if (err) | 454 | if (err) |
454 | return -EFAULT; | 455 | return -EFAULT; |
455 | 456 | ||
@@ -474,6 +475,75 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
474 | } | 475 | } |
475 | #endif /* CONFIG_X86_32 */ | 476 | #endif /* CONFIG_X86_32 */ |
476 | 477 | ||
478 | static int x32_setup_rt_frame(int sig, struct k_sigaction *ka, | ||
479 | siginfo_t *info, compat_sigset_t *set, | ||
480 | struct pt_regs *regs) | ||
481 | { | ||
482 | #ifdef CONFIG_X86_X32_ABI | ||
483 | struct rt_sigframe_x32 __user *frame; | ||
484 | void __user *restorer; | ||
485 | int err = 0; | ||
486 | void __user *fpstate = NULL; | ||
487 | |||
488 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); | ||
489 | |||
490 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
491 | return -EFAULT; | ||
492 | |||
493 | if (ka->sa.sa_flags & SA_SIGINFO) { | ||
494 | if (copy_siginfo_to_user32(&frame->info, info)) | ||
495 | return -EFAULT; | ||
496 | } | ||
497 | |||
498 | put_user_try { | ||
499 | /* Create the ucontext. */ | ||
500 | if (cpu_has_xsave) | ||
501 | put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
502 | else | ||
503 | put_user_ex(0, &frame->uc.uc_flags); | ||
504 | put_user_ex(0, &frame->uc.uc_link); | ||
505 | put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | ||
506 | put_user_ex(sas_ss_flags(regs->sp), | ||
507 | &frame->uc.uc_stack.ss_flags); | ||
508 | put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
509 | put_user_ex(0, &frame->uc.uc__pad0); | ||
510 | |||
511 | if (ka->sa.sa_flags & SA_RESTORER) { | ||
512 | restorer = ka->sa.sa_restorer; | ||
513 | } else { | ||
514 | /* could use a vstub here */ | ||
515 | restorer = NULL; | ||
516 | err |= -EFAULT; | ||
517 | } | ||
518 | put_user_ex(restorer, &frame->pretcode); | ||
519 | } put_user_catch(err); | ||
520 | |||
521 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, | ||
522 | regs, set->sig[0]); | ||
523 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
524 | |||
525 | if (err) | ||
526 | return -EFAULT; | ||
527 | |||
528 | /* Set up registers for signal handler */ | ||
529 | regs->sp = (unsigned long) frame; | ||
530 | regs->ip = (unsigned long) ka->sa.sa_handler; | ||
531 | |||
532 | /* We use the x32 calling convention here... */ | ||
533 | regs->di = sig; | ||
534 | regs->si = (unsigned long) &frame->info; | ||
535 | regs->dx = (unsigned long) &frame->uc; | ||
536 | |||
537 | loadsegment(ds, __USER_DS); | ||
538 | loadsegment(es, __USER_DS); | ||
539 | |||
540 | regs->cs = __USER_CS; | ||
541 | regs->ss = __USER_DS; | ||
542 | #endif /* CONFIG_X86_X32_ABI */ | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
477 | #ifdef CONFIG_X86_32 | 547 | #ifdef CONFIG_X86_32 |
478 | /* | 548 | /* |
479 | * Atomically swap in the new signal mask, and wait for a signal. | 549 | * Atomically swap in the new signal mask, and wait for a signal. |
@@ -612,55 +682,22 @@ static int signr_convert(int sig) | |||
612 | return sig; | 682 | return sig; |
613 | } | 683 | } |
614 | 684 | ||
615 | #ifdef CONFIG_X86_32 | ||
616 | |||
617 | #define is_ia32 1 | ||
618 | #define ia32_setup_frame __setup_frame | ||
619 | #define ia32_setup_rt_frame __setup_rt_frame | ||
620 | |||
621 | #else /* !CONFIG_X86_32 */ | ||
622 | |||
623 | #ifdef CONFIG_IA32_EMULATION | ||
624 | #define is_ia32 test_thread_flag(TIF_IA32) | ||
625 | #else /* !CONFIG_IA32_EMULATION */ | ||
626 | #define is_ia32 0 | ||
627 | #endif /* CONFIG_IA32_EMULATION */ | ||
628 | |||
629 | #ifdef CONFIG_X86_X32_ABI | ||
630 | #define is_x32 test_thread_flag(TIF_X32) | ||
631 | |||
632 | static int x32_setup_rt_frame(int sig, struct k_sigaction *ka, | ||
633 | siginfo_t *info, compat_sigset_t *set, | ||
634 | struct pt_regs *regs); | ||
635 | #else /* !CONFIG_X86_X32_ABI */ | ||
636 | #define is_x32 0 | ||
637 | #endif /* CONFIG_X86_X32_ABI */ | ||
638 | |||
639 | int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
640 | sigset_t *set, struct pt_regs *regs); | ||
641 | int ia32_setup_frame(int sig, struct k_sigaction *ka, | ||
642 | sigset_t *set, struct pt_regs *regs); | ||
643 | |||
644 | #endif /* CONFIG_X86_32 */ | ||
645 | |||
646 | static int | 685 | static int |
647 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 686 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
648 | struct pt_regs *regs) | 687 | struct pt_regs *regs) |
649 | { | 688 | { |
650 | int usig = signr_convert(sig); | 689 | int usig = signr_convert(sig); |
651 | sigset_t *set = sigmask_to_save(); | 690 | sigset_t *set = sigmask_to_save(); |
691 | compat_sigset_t *cset = (compat_sigset_t *) set; | ||
652 | 692 | ||
653 | /* Set up the stack frame */ | 693 | /* Set up the stack frame */ |
654 | if (is_ia32) { | 694 | if (is_ia32_frame()) { |
655 | if (ka->sa.sa_flags & SA_SIGINFO) | 695 | if (ka->sa.sa_flags & SA_SIGINFO) |
656 | return ia32_setup_rt_frame(usig, ka, info, set, regs); | 696 | return ia32_setup_rt_frame(usig, ka, info, cset, regs); |
657 | else | 697 | else |
658 | return ia32_setup_frame(usig, ka, set, regs); | 698 | return ia32_setup_frame(usig, ka, cset, regs); |
659 | #ifdef CONFIG_X86_X32_ABI | 699 | } else if (is_x32_frame()) { |
660 | } else if (is_x32) { | 700 | return x32_setup_rt_frame(usig, ka, info, cset, regs); |
661 | return x32_setup_rt_frame(usig, ka, info, | ||
662 | (compat_sigset_t *)set, regs); | ||
663 | #endif | ||
664 | } else { | 701 | } else { |
665 | return __setup_rt_frame(sig, ka, info, set, regs); | 702 | return __setup_rt_frame(sig, ka, info, set, regs); |
666 | } | 703 | } |
@@ -779,6 +816,8 @@ static void do_signal(struct pt_regs *regs) | |||
779 | void | 816 | void |
780 | do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | 817 | do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) |
781 | { | 818 | { |
819 | rcu_user_exit(); | ||
820 | |||
782 | #ifdef CONFIG_X86_MCE | 821 | #ifdef CONFIG_X86_MCE |
783 | /* notify userspace of pending MCEs */ | 822 | /* notify userspace of pending MCEs */ |
784 | if (thread_info_flags & _TIF_MCE_NOTIFY) | 823 | if (thread_info_flags & _TIF_MCE_NOTIFY) |
@@ -804,6 +843,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | |||
804 | #ifdef CONFIG_X86_32 | 843 | #ifdef CONFIG_X86_32 |
805 | clear_thread_flag(TIF_IRET); | 844 | clear_thread_flag(TIF_IRET); |
806 | #endif /* CONFIG_X86_32 */ | 845 | #endif /* CONFIG_X86_32 */ |
846 | |||
847 | rcu_user_enter(); | ||
807 | } | 848 | } |
808 | 849 | ||
809 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) | 850 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where) |
@@ -824,72 +865,6 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where) | |||
824 | } | 865 | } |
825 | 866 | ||
826 | #ifdef CONFIG_X86_X32_ABI | 867 | #ifdef CONFIG_X86_X32_ABI |
827 | static int x32_setup_rt_frame(int sig, struct k_sigaction *ka, | ||
828 | siginfo_t *info, compat_sigset_t *set, | ||
829 | struct pt_regs *regs) | ||
830 | { | ||
831 | struct rt_sigframe_x32 __user *frame; | ||
832 | void __user *restorer; | ||
833 | int err = 0; | ||
834 | void __user *fpstate = NULL; | ||
835 | |||
836 | frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); | ||
837 | |||
838 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
839 | return -EFAULT; | ||
840 | |||
841 | if (ka->sa.sa_flags & SA_SIGINFO) { | ||
842 | if (copy_siginfo_to_user32(&frame->info, info)) | ||
843 | return -EFAULT; | ||
844 | } | ||
845 | |||
846 | put_user_try { | ||
847 | /* Create the ucontext. */ | ||
848 | if (cpu_has_xsave) | ||
849 | put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); | ||
850 | else | ||
851 | put_user_ex(0, &frame->uc.uc_flags); | ||
852 | put_user_ex(0, &frame->uc.uc_link); | ||
853 | put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | ||
854 | put_user_ex(sas_ss_flags(regs->sp), | ||
855 | &frame->uc.uc_stack.ss_flags); | ||
856 | put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
857 | put_user_ex(0, &frame->uc.uc__pad0); | ||
858 | err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, | ||
859 | regs, set->sig[0]); | ||
860 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
861 | |||
862 | if (ka->sa.sa_flags & SA_RESTORER) { | ||
863 | restorer = ka->sa.sa_restorer; | ||
864 | } else { | ||
865 | /* could use a vstub here */ | ||
866 | restorer = NULL; | ||
867 | err |= -EFAULT; | ||
868 | } | ||
869 | put_user_ex(restorer, &frame->pretcode); | ||
870 | } put_user_catch(err); | ||
871 | |||
872 | if (err) | ||
873 | return -EFAULT; | ||
874 | |||
875 | /* Set up registers for signal handler */ | ||
876 | regs->sp = (unsigned long) frame; | ||
877 | regs->ip = (unsigned long) ka->sa.sa_handler; | ||
878 | |||
879 | /* We use the x32 calling convention here... */ | ||
880 | regs->di = sig; | ||
881 | regs->si = (unsigned long) &frame->info; | ||
882 | regs->dx = (unsigned long) &frame->uc; | ||
883 | |||
884 | loadsegment(ds, __USER_DS); | ||
885 | loadsegment(es, __USER_DS); | ||
886 | |||
887 | regs->cs = __USER_CS; | ||
888 | regs->ss = __USER_DS; | ||
889 | |||
890 | return 0; | ||
891 | } | ||
892 | |||
893 | asmlinkage long sys32_x32_rt_sigreturn(struct pt_regs *regs) | 868 | asmlinkage long sys32_x32_rt_sigreturn(struct pt_regs *regs) |
894 | { | 869 | { |
895 | struct rt_sigframe_x32 __user *frame; | 870 | struct rt_sigframe_x32 __user *frame; |