This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / arch / i386 / kernel / signal.c
index aa242e9..3c50ed2 100644 (file)
@@ -129,28 +129,29 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
  */
 
 static int
-restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax)
+restore_sigcontext(struct pt_regs *regs,
+               struct sigcontext __user *__sc, int *peax)
 {
-       unsigned int err = 0;
+       struct sigcontext scratch; /* 88 bytes of scratch area */
 
        /* Always make any pending restarted system calls return -EINTR */
        current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
-#define COPY(x)                err |= __get_user(regs->x, &sc->x)
+       if (copy_from_user(&scratch, __sc, sizeof(scratch)))
+               return -EFAULT;
+
+#define COPY(x)                regs->x = scratch.x
 
 #define COPY_SEG(seg)                                                  \
-       { unsigned short tmp;                                           \
-         err |= __get_user(tmp, &sc->seg);                             \
+       { unsigned short tmp = scratch.seg;                             \
          regs->x##seg = tmp; }
 
 #define COPY_SEG_STRICT(seg)                                           \
-       { unsigned short tmp;                                           \
-         err |= __get_user(tmp, &sc->seg);                             \
+       { unsigned short tmp = scratch.seg;                             \
          regs->x##seg = tmp|3; }
 
 #define GET_SEG(seg)                                                   \
-       { unsigned short tmp;                                           \
-         err |= __get_user(tmp, &sc->seg);                             \
+       { unsigned short tmp = scratch.seg;                             \
          loadsegment(seg,tmp); }
 
 #define        FIX_EFLAGS      (X86_EFLAGS_AC | X86_EFLAGS_OF | X86_EFLAGS_DF | \
@@ -173,27 +174,23 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax
        COPY_SEG_STRICT(ss);
        
        {
-               unsigned int tmpflags;
-               err |= __get_user(tmpflags, &sc->eflags);
+               unsigned int tmpflags = scratch.eflags;
                regs->eflags = (regs->eflags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
                regs->orig_eax = -1;            /* disable syscall checks */
        }
 
        {
-               struct _fpstate __user * buf;
-               err |= __get_user(buf, &sc->fpstate);
+               struct _fpstate * buf = scratch.fpstate;
                if (buf) {
                        if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
-                               goto badframe;
-                       err |= restore_i387(buf);
+                               return -EFAULT;
+                       if (restore_i387(buf))
+                               return -EFAULT;
                }
        }
 
-       err |= __get_user(*peax, &sc->eax);
-       return err;
-
-badframe:
-       return 1;
+       *peax = scratch.eax;
+       return 0;
 }
 
 asmlinkage int sys_sigreturn(unsigned long __unused)
@@ -231,7 +228,6 @@ asmlinkage int sys_rt_sigreturn(unsigned long __unused)
        struct pt_regs *regs = (struct pt_regs *) &__unused;
        struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(regs->esp - 4);
        sigset_t set;
-       stack_t st;
        int eax;
 
        if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
@@ -248,16 +244,8 @@ asmlinkage int sys_rt_sigreturn(unsigned long __unused)
        if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax))
                goto badframe;
 
-       if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+       if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->esp) == -EFAULT)
                goto badframe;
-       /* It is more difficult to avoid calling this function than to
-          call it and ignore errors.  */
-       /*
-        * THIS CANNOT WORK! "&st" is a kernel address, and "do_sigaltstack()"
-        * takes a user address (and verifies that it is a user address). End
-        * result: it does exactly _nothing_.
-        */
-       do_sigaltstack(&st, NULL, regs->esp);
 
        return eax;
 
@@ -271,46 +259,47 @@ badframe:
  */
 
 static int
-setup_sigcontext(struct sigcontext __user *sc, struct _fpstate __user *fpstate,
+setup_sigcontext(struct sigcontext __user *__sc, struct _fpstate __user *fpstate,
                 struct pt_regs *regs, unsigned long mask)
 {
-       int tmp, err = 0;
+       struct sigcontext sc; /* 88 bytes of scratch area */
+       int tmp;
 
        tmp = 0;
        __asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
-       err |= __put_user(tmp, (unsigned int *)&sc->gs);
+       *(unsigned int *)&sc.gs = tmp;
        __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
-       err |= __put_user(tmp, (unsigned int *)&sc->fs);
-
-       err |= __put_user(regs->xes, (unsigned int *)&sc->es);
-       err |= __put_user(regs->xds, (unsigned int *)&sc->ds);
-       err |= __put_user(regs->edi, &sc->edi);
-       err |= __put_user(regs->esi, &sc->esi);
-       err |= __put_user(regs->ebp, &sc->ebp);
-       err |= __put_user(regs->esp, &sc->esp);
-       err |= __put_user(regs->ebx, &sc->ebx);
-       err |= __put_user(regs->edx, &sc->edx);
-       err |= __put_user(regs->ecx, &sc->ecx);
-       err |= __put_user(regs->eax, &sc->eax);
-       err |= __put_user(current->thread.trap_no, &sc->trapno);
-       err |= __put_user(current->thread.error_code, &sc->err);
-       err |= __put_user(regs->eip, &sc->eip);
-       err |= __put_user(regs->xcs, (unsigned int *)&sc->cs);
-       err |= __put_user(regs->eflags, &sc->eflags);
-       err |= __put_user(regs->esp, &sc->esp_at_signal);
-       err |= __put_user(regs->xss, (unsigned int *)&sc->ss);
+       *(unsigned int *)&sc.fs = tmp;
+       *(unsigned int *)&sc.es = regs->xes;
+       *(unsigned int *)&sc.ds = regs->xds;
+       sc.edi = regs->edi;
+       sc.esi = regs->esi;
+       sc.ebp = regs->ebp;
+       sc.esp = regs->esp;
+       sc.ebx = regs->ebx;
+       sc.edx = regs->edx;
+       sc.ecx = regs->ecx;
+       sc.eax = regs->eax;
+       sc.trapno = current->thread.trap_no;
+       sc.err = current->thread.error_code;
+       sc.eip = regs->eip;
+       *(unsigned int *)&sc.cs = regs->xcs;
+       sc.eflags = regs->eflags;
+       sc.esp_at_signal = regs->esp;
+       *(unsigned int *)&sc.ss = regs->xss;
 
        tmp = save_i387(fpstate);
        if (tmp < 0)
-         err = 1;
-       else
-         err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
+               return 1;
+       sc.fpstate = tmp ? fpstate : NULL;
 
        /* non-iBCS2 extensions.. */
-       err |= __put_user(mask, &sc->oldmask);
-       err |= __put_user(current->thread.cr2, &sc->cr2);
+       sc.oldmask = mask;
+       sc.cr2 = current->thread.cr2;
 
-       return err;
+       if (copy_to_user(__sc, &sc, sizeof(sc)))
+               return 1;
+       return 0;
 }
 
 /*
@@ -342,7 +331,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
 
 /* These symbols are defined with the addresses in the vsyscall page.
    See vsyscall-sigreturn.S.  */
-extern void __kernel_sigreturn, __kernel_rt_sigreturn;
+extern char __kernel_sigreturn, __kernel_rt_sigreturn, SYSENTER_RETURN;
 
 static void setup_frame(int sig, struct k_sigaction *ka,
                        sigset_t *set, struct pt_regs * regs)
@@ -376,7 +365,7 @@ static void setup_frame(int sig, struct k_sigaction *ka,
        if (err)
                goto give_sigsegv;
 
-       restorer = &__kernel_sigreturn;
+       restorer = current->mm->context.vdso + (long)&__kernel_sigreturn;
        if (ka->sa.sa_flags & SA_RESTORER)
                restorer = ka->sa.sa_restorer;
 
@@ -390,9 +379,9 @@ static void setup_frame(int sig, struct k_sigaction *ka,
         * reasons and because gdb uses it as a signature to notice
         * signal handler stack frames.
         */
-       err |= __put_user(0xb858, (short *)(frame->retcode+0));
-       err |= __put_user(__NR_sigreturn, (int *)(frame->retcode+2));
-       err |= __put_user(0x80cd, (short *)(frame->retcode+6));
+       err |= __put_user(0xb858, (short __user *)(frame->retcode+0));
+       err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2));
+       err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
 
        if (err)
                goto give_sigsegv;
@@ -448,7 +437,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        /* Create the ucontext.  */
        err |= __put_user(0, &frame->uc.uc_flags);
        err |= __put_user(0, &frame->uc.uc_link);
-       err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+       err |= __put_user(current->sas_ss_sp, (unsigned long *)&frame->uc.uc_stack.ss_sp);
        err |= __put_user(sas_ss_flags(regs->esp),
                          &frame->uc.uc_stack.ss_flags);
        err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
@@ -459,9 +448,10 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                goto give_sigsegv;
 
        /* Set up to return from userspace.  */
-       restorer = &__kernel_rt_sigreturn;
+       restorer = current->mm->context.vdso + (long)&__kernel_rt_sigreturn;
        if (ka->sa.sa_flags & SA_RESTORER)
                restorer = ka->sa.sa_restorer;
+
        err |= __put_user(restorer, &frame->pretcode);
         
        /*
@@ -471,9 +461,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
         * reasons and because gdb uses it as a signature to notice
         * signal handler stack frames.
         */
-       err |= __put_user(0xb8, (char *)(frame->retcode+0));
-       err |= __put_user(__NR_rt_sigreturn, (int *)(frame->retcode+1));
-       err |= __put_user(0x80cd, (short *)(frame->retcode+5));
+       err |= __put_user(0xb8, (char __user *)(frame->retcode+0));
+       err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1));
+       err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
 
        if (err)
                goto give_sigsegv;