Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
[linux-2.6-microblaze.git] / kernel / signal.c
index caed913..800a18f 100644 (file)
@@ -1194,7 +1194,11 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
                        recalc_sigpending_and_wake(t);
                }
        }
-       if (action->sa.sa_handler == SIG_DFL)
+       /*
+        * Don't clear SIGNAL_UNKILLABLE for traced tasks, users won't expect
+        * debugging to leave init killable.
+        */
+       if (action->sa.sa_handler == SIG_DFL && !t->ptrace)
                t->signal->flags &= ~SIGNAL_UNKILLABLE;
        ret = specific_send_sig_info(sig, info, t);
        spin_unlock_irqrestore(&t->sighand->siglock, flags);
@@ -2682,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)
@@ -2704,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);
@@ -2744,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;
 }
@@ -3303,12 +3345,15 @@ SYSCALL_DEFINE1(sigpending, old_sigset_t __user *, set)
 #ifdef CONFIG_COMPAT
 COMPAT_SYSCALL_DEFINE1(sigpending, compat_old_sigset_t __user *, set32)
 {
+#ifdef __BIG_ENDIAN
        sigset_t set;
-       int err = do_sigpending(&set, sizeof(old_sigset_t)); 
-       if (err == 0)
-               if (copy_to_user(set32, &set, sizeof(old_sigset_t)))
-                       err = -EFAULT;
+       int err = do_sigpending(&set, sizeof(set.sig[0]));
+       if (!err)
+               err = put_user(set.sig[0], set32);
        return err;
+#else
+       return sys_rt_sigpending((sigset_t __user *)set32, sizeof(*set32));
+#endif
 }
 #endif