Merge branch 'work.compat' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[sfrench/cifs-2.6.git] / fs / signalfd.c
index 46e9de097507ae95f00bc427bc48fa400039956a..4fcd1498acf522d75cced6ea13d22b9d78c9b43b 100644 (file)
@@ -81,83 +81,86 @@ static __poll_t signalfd_poll(struct file *file, poll_table *wait)
 static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
                             siginfo_t const *kinfo)
 {
-       long err;
+       struct signalfd_siginfo new;
 
        BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128);
 
        /*
         * Unused members should be zero ...
         */
-       err = __clear_user(uinfo, sizeof(*uinfo));
+       memset(&new, 0, sizeof(new));
 
        /*
         * If you change siginfo_t structure, please be sure
         * this code is fixed accordingly.
         */
-       err |= __put_user(kinfo->si_signo, &uinfo->ssi_signo);
-       err |= __put_user(kinfo->si_errno, &uinfo->ssi_errno);
-       err |= __put_user(kinfo->si_code, &uinfo->ssi_code);
+       new.ssi_signo = kinfo->si_signo;
+       new.ssi_errno = kinfo->si_errno;
+       new.ssi_code  = kinfo->si_code;
        switch (siginfo_layout(kinfo->si_signo, kinfo->si_code)) {
        case SIL_KILL:
-               err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid);
-               err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid);
+               new.ssi_pid = kinfo->si_pid;
+               new.ssi_uid = kinfo->si_uid;
                break;
        case SIL_TIMER:
-                err |= __put_user(kinfo->si_tid, &uinfo->ssi_tid);
-                err |= __put_user(kinfo->si_overrun, &uinfo->ssi_overrun);
-                err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr);
-                err |= __put_user(kinfo->si_int, &uinfo->ssi_int);
+               new.ssi_tid = kinfo->si_tid;
+               new.ssi_overrun = kinfo->si_overrun;
+               new.ssi_ptr = (long) kinfo->si_ptr;
+               new.ssi_int = kinfo->si_int;
                break;
        case SIL_POLL:
-               err |= __put_user(kinfo->si_band, &uinfo->ssi_band);
-               err |= __put_user(kinfo->si_fd, &uinfo->ssi_fd);
+               new.ssi_band = kinfo->si_band;
+               new.ssi_fd   = kinfo->si_fd;
                break;
-       case SIL_FAULT:
-               err |= __put_user((long) kinfo->si_addr, &uinfo->ssi_addr);
-#ifdef __ARCH_SI_TRAPNO
-               err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno);
-#endif
-#ifdef BUS_MCEERR_AO
+       case SIL_FAULT_BNDERR:
+       case SIL_FAULT_PKUERR:
                /*
-                * Other callers might not initialize the si_lsb field,
-                * so check explicitly for the right codes here.
+                * Fall through to the SIL_FAULT case.  Both SIL_FAULT_BNDERR
+                * and SIL_FAULT_PKUERR are only generated by faults that
+                * deliver them synchronously to userspace.  In case someone
+                * injects one of these signals and signalfd catches it treat
+                * it as SIL_FAULT.
                 */
-               if (kinfo->si_signo == SIGBUS &&
-                    kinfo->si_code == BUS_MCEERR_AO)
-                       err |= __put_user((short) kinfo->si_addr_lsb,
-                                         &uinfo->ssi_addr_lsb);
+       case SIL_FAULT:
+               new.ssi_addr = (long) kinfo->si_addr;
+#ifdef __ARCH_SI_TRAPNO
+               new.ssi_trapno = kinfo->si_trapno;
 #endif
-#ifdef BUS_MCEERR_AR
-               /*
-                * Other callers might not initialize the si_lsb field,
-                * so check explicitly for the right codes here.
-                */
-               if (kinfo->si_signo == SIGBUS &&
-                   kinfo->si_code == BUS_MCEERR_AR)
-                       err |= __put_user((short) kinfo->si_addr_lsb,
-                                         &uinfo->ssi_addr_lsb);
+               break;
+       case SIL_FAULT_MCEERR:
+               new.ssi_addr = (long) kinfo->si_addr;
+#ifdef __ARCH_SI_TRAPNO
+               new.ssi_trapno = kinfo->si_trapno;
 #endif
+               new.ssi_addr_lsb = (short) kinfo->si_addr_lsb;
                break;
        case SIL_CHLD:
-               err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid);
-               err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid);
-               err |= __put_user(kinfo->si_status, &uinfo->ssi_status);
-               err |= __put_user(kinfo->si_utime, &uinfo->ssi_utime);
-               err |= __put_user(kinfo->si_stime, &uinfo->ssi_stime);
+               new.ssi_pid    = kinfo->si_pid;
+               new.ssi_uid    = kinfo->si_uid;
+               new.ssi_status = kinfo->si_status;
+               new.ssi_utime  = kinfo->si_utime;
+               new.ssi_stime  = kinfo->si_stime;
                break;
        case SIL_RT:
-       default:
                /*
                 * This case catches also the signals queued by sigqueue().
                 */
-               err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid);
-               err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid);
-               err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr);
-               err |= __put_user(kinfo->si_int, &uinfo->ssi_int);
+               new.ssi_pid = kinfo->si_pid;
+               new.ssi_uid = kinfo->si_uid;
+               new.ssi_ptr = (long) kinfo->si_ptr;
+               new.ssi_int = kinfo->si_int;
+               break;
+       case SIL_SYS:
+               new.ssi_call_addr = (long) kinfo->si_call_addr;
+               new.ssi_syscall   = kinfo->si_syscall;
+               new.ssi_arch      = kinfo->si_arch;
                break;
        }
 
-       return err ? -EFAULT: sizeof(*uinfo);
+       if (copy_to_user(uinfo, &new, sizeof(struct signalfd_siginfo)))
+               return -EFAULT;
+
+       return sizeof(*uinfo);
 }
 
 static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, siginfo_t *info,