diff options
Diffstat (limited to 'arch/x86/kernel/signal.c')
-rw-r--r-- | arch/x86/kernel/signal.c | 52 |
1 files changed, 26 insertions, 26 deletions
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index e5042463c1bc..3e581865c8e2 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
@@ -61,8 +61,7 @@ | |||
61 | regs->seg = GET_SEG(seg) | 3; \ | 61 | regs->seg = GET_SEG(seg) | 3; \ |
62 | } while (0) | 62 | } while (0) |
63 | 63 | ||
64 | int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | 64 | int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) |
65 | unsigned long *pax) | ||
66 | { | 65 | { |
67 | void __user *buf; | 66 | void __user *buf; |
68 | unsigned int tmpflags; | 67 | unsigned int tmpflags; |
@@ -81,7 +80,7 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
81 | #endif /* CONFIG_X86_32 */ | 80 | #endif /* CONFIG_X86_32 */ |
82 | 81 | ||
83 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); | 82 | COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); |
84 | COPY(dx); COPY(cx); COPY(ip); | 83 | COPY(dx); COPY(cx); COPY(ip); COPY(ax); |
85 | 84 | ||
86 | #ifdef CONFIG_X86_64 | 85 | #ifdef CONFIG_X86_64 |
87 | COPY(r8); | 86 | COPY(r8); |
@@ -94,27 +93,20 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
94 | COPY(r15); | 93 | COPY(r15); |
95 | #endif /* CONFIG_X86_64 */ | 94 | #endif /* CONFIG_X86_64 */ |
96 | 95 | ||
97 | #ifdef CONFIG_X86_32 | ||
98 | COPY_SEG_CPL3(cs); | 96 | COPY_SEG_CPL3(cs); |
99 | COPY_SEG_CPL3(ss); | 97 | COPY_SEG_CPL3(ss); |
100 | #else /* !CONFIG_X86_32 */ | ||
101 | /* Kernel saves and restores only the CS segment register on signals, | ||
102 | * which is the bare minimum needed to allow mixed 32/64-bit code. | ||
103 | * App's signal handler can save/restore other segments if needed. */ | ||
104 | COPY_SEG_CPL3(cs); | ||
105 | #endif /* CONFIG_X86_32 */ | ||
106 | 98 | ||
107 | get_user_ex(tmpflags, &sc->flags); | 99 | get_user_ex(tmpflags, &sc->flags); |
108 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); | 100 | regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS); |
109 | regs->orig_ax = -1; /* disable syscall checks */ | 101 | regs->orig_ax = -1; /* disable syscall checks */ |
110 | 102 | ||
111 | get_user_ex(buf, &sc->fpstate); | 103 | get_user_ex(buf, &sc->fpstate); |
112 | |||
113 | get_user_ex(*pax, &sc->ax); | ||
114 | } get_user_catch(err); | 104 | } get_user_catch(err); |
115 | 105 | ||
116 | err |= restore_xstate_sig(buf, config_enabled(CONFIG_X86_32)); | 106 | err |= restore_xstate_sig(buf, config_enabled(CONFIG_X86_32)); |
117 | 107 | ||
108 | force_iret(); | ||
109 | |||
118 | return err; | 110 | return err; |
119 | } | 111 | } |
120 | 112 | ||
@@ -162,8 +154,9 @@ int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, | |||
162 | #else /* !CONFIG_X86_32 */ | 154 | #else /* !CONFIG_X86_32 */ |
163 | put_user_ex(regs->flags, &sc->flags); | 155 | put_user_ex(regs->flags, &sc->flags); |
164 | put_user_ex(regs->cs, &sc->cs); | 156 | put_user_ex(regs->cs, &sc->cs); |
165 | put_user_ex(0, &sc->gs); | 157 | put_user_ex(0, &sc->__pad2); |
166 | put_user_ex(0, &sc->fs); | 158 | put_user_ex(0, &sc->__pad1); |
159 | put_user_ex(regs->ss, &sc->ss); | ||
167 | #endif /* CONFIG_X86_32 */ | 160 | #endif /* CONFIG_X86_32 */ |
168 | 161 | ||
169 | put_user_ex(fpstate, &sc->fpstate); | 162 | put_user_ex(fpstate, &sc->fpstate); |
@@ -457,9 +450,19 @@ static int __setup_rt_frame(int sig, struct ksignal *ksig, | |||
457 | 450 | ||
458 | regs->sp = (unsigned long)frame; | 451 | regs->sp = (unsigned long)frame; |
459 | 452 | ||
460 | /* Set up the CS register to run signal handlers in 64-bit mode, | 453 | /* |
461 | even if the handler happens to be interrupting 32-bit code. */ | 454 | * Set up the CS and SS registers to run signal handlers in |
455 | * 64-bit mode, even if the handler happens to be interrupting | ||
456 | * 32-bit or 16-bit code. | ||
457 | * | ||
458 | * SS is subtle. In 64-bit mode, we don't need any particular | ||
459 | * SS descriptor, but we do need SS to be valid. It's possible | ||
460 | * that the old SS is entirely bogus -- this can happen if the | ||
461 | * signal we're trying to deliver is #GP or #SS caused by a bad | ||
462 | * SS value. | ||
463 | */ | ||
462 | regs->cs = __USER_CS; | 464 | regs->cs = __USER_CS; |
465 | regs->ss = __USER_DS; | ||
463 | 466 | ||
464 | return 0; | 467 | return 0; |
465 | } | 468 | } |
@@ -539,7 +542,6 @@ asmlinkage unsigned long sys_sigreturn(void) | |||
539 | { | 542 | { |
540 | struct pt_regs *regs = current_pt_regs(); | 543 | struct pt_regs *regs = current_pt_regs(); |
541 | struct sigframe __user *frame; | 544 | struct sigframe __user *frame; |
542 | unsigned long ax; | ||
543 | sigset_t set; | 545 | sigset_t set; |
544 | 546 | ||
545 | frame = (struct sigframe __user *)(regs->sp - 8); | 547 | frame = (struct sigframe __user *)(regs->sp - 8); |
@@ -553,9 +555,9 @@ asmlinkage unsigned long sys_sigreturn(void) | |||
553 | 555 | ||
554 | set_current_blocked(&set); | 556 | set_current_blocked(&set); |
555 | 557 | ||
556 | if (restore_sigcontext(regs, &frame->sc, &ax)) | 558 | if (restore_sigcontext(regs, &frame->sc)) |
557 | goto badframe; | 559 | goto badframe; |
558 | return ax; | 560 | return regs->ax; |
559 | 561 | ||
560 | badframe: | 562 | badframe: |
561 | signal_fault(regs, frame, "sigreturn"); | 563 | signal_fault(regs, frame, "sigreturn"); |
@@ -568,7 +570,6 @@ asmlinkage long sys_rt_sigreturn(void) | |||
568 | { | 570 | { |
569 | struct pt_regs *regs = current_pt_regs(); | 571 | struct pt_regs *regs = current_pt_regs(); |
570 | struct rt_sigframe __user *frame; | 572 | struct rt_sigframe __user *frame; |
571 | unsigned long ax; | ||
572 | sigset_t set; | 573 | sigset_t set; |
573 | 574 | ||
574 | frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); | 575 | frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long)); |
@@ -579,13 +580,13 @@ asmlinkage long sys_rt_sigreturn(void) | |||
579 | 580 | ||
580 | set_current_blocked(&set); | 581 | set_current_blocked(&set); |
581 | 582 | ||
582 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) | 583 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) |
583 | goto badframe; | 584 | goto badframe; |
584 | 585 | ||
585 | if (restore_altstack(&frame->uc.uc_stack)) | 586 | if (restore_altstack(&frame->uc.uc_stack)) |
586 | goto badframe; | 587 | goto badframe; |
587 | 588 | ||
588 | return ax; | 589 | return regs->ax; |
589 | 590 | ||
590 | badframe: | 591 | badframe: |
591 | signal_fault(regs, frame, "rt_sigreturn"); | 592 | signal_fault(regs, frame, "rt_sigreturn"); |
@@ -679,7 +680,7 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs) | |||
679 | * Ensure the signal handler starts with the new fpu state. | 680 | * Ensure the signal handler starts with the new fpu state. |
680 | */ | 681 | */ |
681 | if (used_math()) | 682 | if (used_math()) |
682 | drop_init_fpu(current); | 683 | fpu_reset_state(current); |
683 | } | 684 | } |
684 | signal_setup_done(failed, ksig, test_thread_flag(TIF_SINGLESTEP)); | 685 | signal_setup_done(failed, ksig, test_thread_flag(TIF_SINGLESTEP)); |
685 | } | 686 | } |
@@ -780,7 +781,6 @@ asmlinkage long sys32_x32_rt_sigreturn(void) | |||
780 | struct pt_regs *regs = current_pt_regs(); | 781 | struct pt_regs *regs = current_pt_regs(); |
781 | struct rt_sigframe_x32 __user *frame; | 782 | struct rt_sigframe_x32 __user *frame; |
782 | sigset_t set; | 783 | sigset_t set; |
783 | unsigned long ax; | ||
784 | 784 | ||
785 | frame = (struct rt_sigframe_x32 __user *)(regs->sp - 8); | 785 | frame = (struct rt_sigframe_x32 __user *)(regs->sp - 8); |
786 | 786 | ||
@@ -791,13 +791,13 @@ asmlinkage long sys32_x32_rt_sigreturn(void) | |||
791 | 791 | ||
792 | set_current_blocked(&set); | 792 | set_current_blocked(&set); |
793 | 793 | ||
794 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) | 794 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) |
795 | goto badframe; | 795 | goto badframe; |
796 | 796 | ||
797 | if (compat_restore_altstack(&frame->uc.uc_stack)) | 797 | if (compat_restore_altstack(&frame->uc.uc_stack)) |
798 | goto badframe; | 798 | goto badframe; |
799 | 799 | ||
800 | return ax; | 800 | return regs->ax; |
801 | 801 | ||
802 | badframe: | 802 | badframe: |
803 | signal_fault(regs, frame, "x32 rt_sigreturn"); | 803 | signal_fault(regs, frame, "x32 rt_sigreturn"); |