diff options
Diffstat (limited to 'arch/x86/kernel/signal.c')
-rw-r--r-- | arch/x86/kernel/signal.c | 75 |
1 files changed, 20 insertions, 55 deletions
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 7fc78b019815..7cdcd16885ed 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
@@ -50,27 +50,23 @@ | |||
50 | # define FIX_EFLAGS __FIX_EFLAGS | 50 | # define FIX_EFLAGS __FIX_EFLAGS |
51 | #endif | 51 | #endif |
52 | 52 | ||
53 | #define COPY(x) { \ | 53 | #define COPY(x) do { \ |
54 | get_user_ex(regs->x, &sc->x); \ | 54 | get_user_ex(regs->x, &sc->x); \ |
55 | } | 55 | } while (0) |
56 | 56 | ||
57 | #define COPY_SEG(seg) { \ | 57 | #define GET_SEG(seg) ({ \ |
58 | unsigned short tmp; \ | 58 | unsigned short tmp; \ |
59 | get_user_ex(tmp, &sc->seg); \ | 59 | get_user_ex(tmp, &sc->seg); \ |
60 | regs->seg = tmp; \ | 60 | tmp; \ |
61 | } | 61 | }) |
62 | 62 | ||
63 | #define COPY_SEG_CPL3(seg) { \ | 63 | #define COPY_SEG(seg) do { \ |
64 | unsigned short tmp; \ | 64 | regs->seg = GET_SEG(seg); \ |
65 | get_user_ex(tmp, &sc->seg); \ | 65 | } while (0) |
66 | regs->seg = tmp | 3; \ | ||
67 | } | ||
68 | 66 | ||
69 | #define GET_SEG(seg) { \ | 67 | #define COPY_SEG_CPL3(seg) do { \ |
70 | unsigned short tmp; \ | 68 | regs->seg = GET_SEG(seg) | 3; \ |
71 | get_user_ex(tmp, &sc->seg); \ | 69 | } while (0) |
72 | loadsegment(seg, tmp); \ | ||
73 | } | ||
74 | 70 | ||
75 | static int | 71 | static int |
76 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | 72 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, |
@@ -86,7 +82,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, | |||
86 | get_user_try { | 82 | get_user_try { |
87 | 83 | ||
88 | #ifdef CONFIG_X86_32 | 84 | #ifdef CONFIG_X86_32 |
89 | GET_SEG(gs); | 85 | set_user_gs(regs, GET_SEG(gs)); |
90 | COPY_SEG(fs); | 86 | COPY_SEG(fs); |
91 | COPY_SEG(es); | 87 | COPY_SEG(es); |
92 | COPY_SEG(ds); | 88 | COPY_SEG(ds); |
@@ -138,12 +134,7 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, | |||
138 | put_user_try { | 134 | put_user_try { |
139 | 135 | ||
140 | #ifdef CONFIG_X86_32 | 136 | #ifdef CONFIG_X86_32 |
141 | { | 137 | put_user_ex(get_user_gs(regs), (unsigned int __user *)&sc->gs); |
142 | unsigned int tmp; | ||
143 | |||
144 | savesegment(gs, tmp); | ||
145 | put_user_ex(tmp, (unsigned int __user *)&sc->gs); | ||
146 | } | ||
147 | put_user_ex(regs->fs, (unsigned int __user *)&sc->fs); | 138 | put_user_ex(regs->fs, (unsigned int __user *)&sc->fs); |
148 | put_user_ex(regs->es, (unsigned int __user *)&sc->es); | 139 | put_user_ex(regs->es, (unsigned int __user *)&sc->es); |
149 | put_user_ex(regs->ds, (unsigned int __user *)&sc->ds); | 140 | put_user_ex(regs->ds, (unsigned int __user *)&sc->ds); |
@@ -558,14 +549,9 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
558 | #endif /* CONFIG_X86_32 */ | 549 | #endif /* CONFIG_X86_32 */ |
559 | 550 | ||
560 | #ifdef CONFIG_X86_32 | 551 | #ifdef CONFIG_X86_32 |
561 | asmlinkage int sys_sigaltstack(unsigned long bx) | 552 | int sys_sigaltstack(struct pt_regs *regs) |
562 | { | 553 | { |
563 | /* | 554 | const stack_t __user *uss = (const stack_t __user *)regs->bx; |
564 | * This is needed to make gcc realize it doesn't own the | ||
565 | * "struct pt_regs" | ||
566 | */ | ||
567 | struct pt_regs *regs = (struct pt_regs *)&bx; | ||
568 | const stack_t __user *uss = (const stack_t __user *)bx; | ||
569 | stack_t __user *uoss = (stack_t __user *)regs->cx; | 555 | stack_t __user *uoss = (stack_t __user *)regs->cx; |
570 | 556 | ||
571 | return do_sigaltstack(uss, uoss, regs->sp); | 557 | return do_sigaltstack(uss, uoss, regs->sp); |
@@ -583,14 +569,12 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | |||
583 | * Do a signal return; undo the signal stack. | 569 | * Do a signal return; undo the signal stack. |
584 | */ | 570 | */ |
585 | #ifdef CONFIG_X86_32 | 571 | #ifdef CONFIG_X86_32 |
586 | asmlinkage unsigned long sys_sigreturn(unsigned long __unused) | 572 | unsigned long sys_sigreturn(struct pt_regs *regs) |
587 | { | 573 | { |
588 | struct sigframe __user *frame; | 574 | struct sigframe __user *frame; |
589 | struct pt_regs *regs; | ||
590 | unsigned long ax; | 575 | unsigned long ax; |
591 | sigset_t set; | 576 | sigset_t set; |
592 | 577 | ||
593 | regs = (struct pt_regs *) &__unused; | ||
594 | frame = (struct sigframe __user *)(regs->sp - 8); | 578 | frame = (struct sigframe __user *)(regs->sp - 8); |
595 | 579 | ||
596 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 580 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
@@ -617,7 +601,7 @@ badframe: | |||
617 | } | 601 | } |
618 | #endif /* CONFIG_X86_32 */ | 602 | #endif /* CONFIG_X86_32 */ |
619 | 603 | ||
620 | static long do_rt_sigreturn(struct pt_regs *regs) | 604 | long sys_rt_sigreturn(struct pt_regs *regs) |
621 | { | 605 | { |
622 | struct rt_sigframe __user *frame; | 606 | struct rt_sigframe __user *frame; |
623 | unsigned long ax; | 607 | unsigned long ax; |
@@ -648,25 +632,6 @@ badframe: | |||
648 | return 0; | 632 | return 0; |
649 | } | 633 | } |
650 | 634 | ||
651 | #ifdef CONFIG_X86_32 | ||
652 | /* | ||
653 | * Note: do not pass in pt_regs directly as with tail-call optimization | ||
654 | * GCC will incorrectly stomp on the caller's frame and corrupt user-space | ||
655 | * register state: | ||
656 | */ | ||
657 | asmlinkage int sys_rt_sigreturn(unsigned long __unused) | ||
658 | { | ||
659 | struct pt_regs *regs = (struct pt_regs *)&__unused; | ||
660 | |||
661 | return do_rt_sigreturn(regs); | ||
662 | } | ||
663 | #else /* !CONFIG_X86_32 */ | ||
664 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | ||
665 | { | ||
666 | return do_rt_sigreturn(regs); | ||
667 | } | ||
668 | #endif /* CONFIG_X86_32 */ | ||
669 | |||
670 | /* | 635 | /* |
671 | * OK, we're invoking a handler: | 636 | * OK, we're invoking a handler: |
672 | */ | 637 | */ |