Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi...
[sfrench/cifs-2.6.git] / kernel / signal.c
index ed804a470dcd151c18915f956c2f325b6d22bb0f..800a18f77732c14cf49d81bc615b01cd56d11933 100644 (file)
@@ -2686,6 +2686,51 @@ COMPAT_SYSCALL_DEFINE2(rt_sigpending, compat_sigset_t __user *, uset,
 }
 #endif
 
+enum siginfo_layout siginfo_layout(int sig, int si_code)
+{
+       enum siginfo_layout layout = SIL_KILL;
+       if ((si_code > SI_USER) && (si_code < SI_KERNEL)) {
+               static const struct {
+                       unsigned char limit, layout;
+               } filter[] = {
+                       [SIGILL]  = { NSIGILL,  SIL_FAULT },
+                       [SIGFPE]  = { NSIGFPE,  SIL_FAULT },
+                       [SIGSEGV] = { NSIGSEGV, SIL_FAULT },
+                       [SIGBUS]  = { NSIGBUS,  SIL_FAULT },
+                       [SIGTRAP] = { NSIGTRAP, SIL_FAULT },
+#if defined(SIGMET) && defined(NSIGEMT)
+                       [SIGEMT]  = { NSIGEMT,  SIL_FAULT },
+#endif
+                       [SIGCHLD] = { NSIGCHLD, SIL_CHLD },
+                       [SIGPOLL] = { NSIGPOLL, SIL_POLL },
+#ifdef __ARCH_SIGSYS
+                       [SIGSYS]  = { NSIGSYS,  SIL_SYS },
+#endif
+               };
+               if ((sig < ARRAY_SIZE(filter)) && (si_code <= filter[sig].limit))
+                       layout = filter[sig].layout;
+               else if (si_code <= NSIGPOLL)
+                       layout = SIL_POLL;
+       } else {
+               if (si_code == SI_TIMER)
+                       layout = SIL_TIMER;
+               else if (si_code == SI_SIGIO)
+                       layout = SIL_POLL;
+               else if (si_code < 0)
+                       layout = SIL_RT;
+               /* Tests to support buggy kernel ABIs */
+#ifdef TRAP_FIXME
+               if ((sig == SIGTRAP) && (si_code == TRAP_FIXME))
+                       layout = SIL_FAULT;
+#endif
+#ifdef FPE_FIXME
+               if ((sig == SIGFPE) && (si_code == FPE_FIXME))
+                       layout = SIL_FAULT;
+#endif
+       }
+       return layout;
+}
+
 #ifndef HAVE_ARCH_COPY_SIGINFO_TO_USER
 
 int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
@@ -2708,22 +2753,20 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
         */
        err = __put_user(from->si_signo, &to->si_signo);
        err |= __put_user(from->si_errno, &to->si_errno);
-       err |= __put_user((short)from->si_code, &to->si_code);
-       switch (from->si_code & __SI_MASK) {
-       case __SI_KILL:
+       err |= __put_user(from->si_code, &to->si_code);
+       switch (siginfo_layout(from->si_signo, from->si_code)) {
+       case SIL_KILL:
                err |= __put_user(from->si_pid, &to->si_pid);
                err |= __put_user(from->si_uid, &to->si_uid);
                break;
-       case __SI_TIMER:
-                err |= __put_user(from->si_tid, &to->si_tid);
-                err |= __put_user(from->si_overrun, &to->si_overrun);
-                err |= __put_user(from->si_ptr, &to->si_ptr);
+       case SIL_TIMER:
+               /* Unreached SI_TIMER is negative */
                break;
-       case __SI_POLL:
+       case SIL_POLL:
                err |= __put_user(from->si_band, &to->si_band);
                err |= __put_user(from->si_fd, &to->si_fd);
                break;
-       case __SI_FAULT:
+       case SIL_FAULT:
                err |= __put_user(from->si_addr, &to->si_addr);
 #ifdef __ARCH_SI_TRAPNO
                err |= __put_user(from->si_trapno, &to->si_trapno);
@@ -2748,30 +2791,25 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
                        err |= __put_user(from->si_pkey, &to->si_pkey);
 #endif
                break;
-       case __SI_CHLD:
+       case SIL_CHLD:
                err |= __put_user(from->si_pid, &to->si_pid);
                err |= __put_user(from->si_uid, &to->si_uid);
                err |= __put_user(from->si_status, &to->si_status);
                err |= __put_user(from->si_utime, &to->si_utime);
                err |= __put_user(from->si_stime, &to->si_stime);
                break;
-       case __SI_RT: /* This is not generated by the kernel as of now. */
-       case __SI_MESGQ: /* But this is */
+       case SIL_RT:
                err |= __put_user(from->si_pid, &to->si_pid);
                err |= __put_user(from->si_uid, &to->si_uid);
                err |= __put_user(from->si_ptr, &to->si_ptr);
                break;
 #ifdef __ARCH_SIGSYS
-       case __SI_SYS:
+       case SIL_SYS:
                err |= __put_user(from->si_call_addr, &to->si_call_addr);
                err |= __put_user(from->si_syscall, &to->si_syscall);
                err |= __put_user(from->si_arch, &to->si_arch);
                break;
 #endif
-       default: /* this is just in case for now ... */
-               err |= __put_user(from->si_pid, &to->si_pid);
-               err |= __put_user(from->si_uid, &to->si_uid);
-               break;
        }
        return err;
 }