VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / arch / s390 / kernel / compat_signal.c
index 3886a27..e8c8b2f 100644 (file)
@@ -40,6 +40,7 @@ typedef struct
        __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
        struct sigcontext32 sc;
        _sigregs32 sregs;
+       int signo;
        __u8 retcode[S390_SYSCALL_SIZE];
 } sigframe32;
 
@@ -53,7 +54,7 @@ typedef struct
 
 asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
 
-int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from)
+int copy_siginfo_to_user32(siginfo_t32 __user *to, siginfo_t *from)
 {
        int err;
 
@@ -105,6 +106,53 @@ int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from)
        return err;
 }
 
+int copy_siginfo_from_user32(siginfo_t *to, siginfo_t32 __user *from)
+{
+       int err;
+       u32 tmp;
+
+       if (!access_ok (VERIFY_READ, from, sizeof(siginfo_t32)))
+               return -EFAULT;
+
+       err = __get_user(to->si_signo, &from->si_signo);
+       err |= __get_user(to->si_errno, &from->si_errno);
+       err |= __get_user(to->si_code, &from->si_code);
+
+       if (from->si_code < 0)
+               err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
+       else {
+               switch (from->si_code >> 16) {
+               case __SI_RT >> 16: /* This is not generated by the kernel as of now.  */
+               case __SI_MESGQ >> 16:
+                       err |= __get_user(to->si_int, &from->si_int);
+                       /* fallthrough */
+               case __SI_KILL >> 16:
+                       err |= __get_user(to->si_pid, &from->si_pid);
+                       err |= __get_user(to->si_uid, &from->si_uid);
+                       break;
+               case __SI_CHLD >> 16:
+                       err |= __get_user(to->si_pid, &from->si_pid);
+                       err |= __get_user(to->si_uid, &from->si_uid);
+                       err |= __get_user(to->si_utime, &from->si_utime);
+                       err |= __get_user(to->si_stime, &from->si_stime);
+                       err |= __get_user(to->si_status, &from->si_status);
+                       break;
+               case __SI_FAULT >> 16:
+                       err |= __get_user(tmp, &from->si_addr);
+                       to->si_addr = (void *)(u64) (tmp & PSW32_ADDR_INSN);
+                       break;
+               case __SI_POLL >> 16:
+               case __SI_TIMER >> 16:
+                       err |= __get_user(to->si_band, &from->si_band);
+                       err |= __get_user(to->si_fd, &from->si_fd);
+                       break;
+               default:
+                       break;
+               }
+       }
+       return err;
+}
+
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
@@ -130,7 +178,8 @@ sys32_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t
 }
 
 asmlinkage int
-sys32_rt_sigsuspend(struct pt_regs * regs,compat_sigset_t *unewset, size_t sigsetsize)
+sys32_rt_sigsuspend(struct pt_regs * regs, compat_sigset_t __user *unewset,
+                                                               size_t sigsetsize)
 {
        sigset_t saveset, newset;
        compat_sigset_t set32;
@@ -162,11 +211,11 @@ sys32_rt_sigsuspend(struct pt_regs * regs,compat_sigset_t *unewset, size_t sigse
                 if (do_signal(regs, &saveset))
                         return -EINTR;
         }
-}                                                         
+}
 
 asmlinkage long
-sys32_sigaction(int sig, const struct old_sigaction32 *act,
-                struct old_sigaction32 *oact)
+sys32_sigaction(int sig, const struct old_sigaction32 __user *act,
+                struct old_sigaction32 __user *oact)
 {
         struct k_sigaction new_ka, old_ka;
         int ret;
@@ -199,9 +248,9 @@ sys32_sigaction(int sig, const struct old_sigaction32 *act,
 int
 do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact);
 
-asmlinkage long 
-sys32_rt_sigaction(int sig, const struct sigaction32 *act,
-          struct sigaction32 *oact,  size_t sigsetsize)
+asmlinkage long
+sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
+          struct sigaction32 __user *oact,  size_t sigsetsize)
 {
        struct k_sigaction new_ka, old_ka;
        int ret;
@@ -258,7 +307,8 @@ sys32_rt_sigaction(int sig, const struct sigaction32 *act,
 }
 
 asmlinkage long
-sys32_sigaltstack(const stack_t32 *uss, stack_t32 *uoss, struct pt_regs *regs)
+sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss,
+                                                       struct pt_regs *regs)
 {
        stack_t kss, koss;
        int ret, err = 0;
@@ -275,7 +325,9 @@ sys32_sigaltstack(const stack_t32 *uss, stack_t32 *uoss, struct pt_regs *regs)
        }
 
        set_fs (KERNEL_DS);
-       ret = do_sigaltstack(uss ? &kss : NULL , uoss ? &koss : NULL, regs->gprs[15]);
+       ret = do_sigaltstack((stack_t __user *) (uss ? &kss : NULL),
+                            (stack_t __user *) (uoss ? &koss : NULL),
+                            regs->gprs[15]);
        set_fs (old_fs);
 
        if (!ret && uoss) {
@@ -290,7 +342,7 @@ sys32_sigaltstack(const stack_t32 *uss, stack_t32 *uoss, struct pt_regs *regs)
        return ret;
 }
 
-static int save_sigregs32(struct pt_regs *regs,_sigregs32 *sregs)
+static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
 {
        _s390_regs_common32 regs32;
        int err, i;
@@ -311,7 +363,7 @@ static int save_sigregs32(struct pt_regs *regs,_sigregs32 *sregs)
                              sizeof(_s390_fp_regs32));
 }
 
-static int restore_sigregs32(struct pt_regs *regs,_sigregs32 *sregs)
+static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
 {
        _s390_regs_common32 regs32;
        int err, i;
@@ -343,7 +395,7 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 *sregs)
 
 asmlinkage long sys32_sigreturn(struct pt_regs *regs)
 {
-       sigframe32 *frame = (sigframe32 *)regs->gprs[15];
+       sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
        sigset_t set;
 
        if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
@@ -365,11 +417,11 @@ asmlinkage long sys32_sigreturn(struct pt_regs *regs)
 badframe:
        force_sig(SIGSEGV, current);
        return 0;
-}      
+}
 
 asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
 {
-       rt_sigframe32 *frame = (rt_sigframe32 *)regs->gprs[15];
+       rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
        sigset_t set;
        stack_t st;
        __u32 ss_sp;
@@ -399,8 +451,8 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
 
        /* It is more difficult to avoid calling this function than to
           call it and ignore errors.  */
-       set_fs (KERNEL_DS);   
-       do_sigaltstack(&st, NULL, regs->gprs[15]);
+       set_fs (KERNEL_DS);
+       do_sigaltstack((stack_t __user *)&st, NULL, regs->gprs[15]);
        set_fs (old_fs);
 
        return regs->gprs[2];
@@ -418,7 +470,7 @@ badframe:
 /*
  * Determine which stack to use..
  */
-static inline void *
+static inline void __user *
 get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
 {
        unsigned long sp;
@@ -439,7 +491,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
                sp = (unsigned long) ka->sa.sa_restorer;
        }
 
-       return (void *)((sp - frame_size) & -8ul);
+       return (void __user *)((sp - frame_size) & -8ul);
 }
 
 static inline int map_signal(int sig)
@@ -455,7 +507,7 @@ static inline int map_signal(int sig)
 static void setup_frame32(int sig, struct k_sigaction *ka,
                        sigset_t *set, struct pt_regs * regs)
 {
-       sigframe32 *frame = get_sigframe(ka, regs, sizeof(sigframe32));
+       sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32));
        if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32)))
                goto give_sigsegv;
 
@@ -474,12 +526,12 @@ static void setup_frame32(int sig, struct k_sigaction *ka,
        } else {
                regs->gprs[14] = (__u64) frame->retcode;
                if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
-                              (u16 *)(frame->retcode)))
+                              (u16 __user *)(frame->retcode)))
                        goto give_sigsegv;
         }
 
        /* Set up backchain. */
-       if (__put_user(regs->gprs[15], (unsigned int *) frame))
+       if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
                goto give_sigsegv;
 
        /* Set up registers for signal handler */
@@ -493,6 +545,10 @@ static void setup_frame32(int sig, struct k_sigaction *ka,
           To avoid breaking binary compatibility, they are passed as args. */
        regs->gprs[4] = current->thread.trap_no;
        regs->gprs[5] = current->thread.prot_addr;
+
+       /* Place signal number on stack to allow backtrace from handler.  */
+       if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
+               goto give_sigsegv;
        return;
 
 give_sigsegv:
@@ -505,7 +561,7 @@ static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
                           sigset_t *set, struct pt_regs * regs)
 {
        int err = 0;
-       rt_sigframe32 *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32));
+       rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32));
        if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32)))
                goto give_sigsegv;
 
@@ -531,11 +587,11 @@ static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
        } else {
                regs->gprs[14] = (__u64) frame->retcode;
                err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
-                                 (u16 *)(frame->retcode));
+                                 (u16 __user *)(frame->retcode));
        }
 
        /* Set up backchain. */
-       if (__put_user(regs->gprs[15], (unsigned int *) frame))
+       if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
                goto give_sigsegv;
 
        /* Set up registers for signal handler */