Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livep...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 31 Jan 2018 21:02:18 +0000 (13:02 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 31 Jan 2018 21:02:18 +0000 (13:02 -0800)
Pull livepatching updates from Jiri Kosina:

 - handle 'infinitely'-long sleeping tasks, from Miroslav Benes

 - remove 'immediate' feature, as it turns out it doesn't provide the
   originally expected semantics, and brings more issues than value

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching:
  livepatch: add locking to force and signal functions
  livepatch: Remove immediate feature
  livepatch: force transition to finish
  livepatch: send a fake signal to all blocking tasks

1  2 
arch/powerpc/kernel/signal.c
kernel/signal.c

index 3d7539b90010c6114655f3f909de64c65f09686a,bf9c4e7792d1bae92f4bdec4b564411112c588e8..61db86ecd318d8d7a027b28e6d8aebf19e06f528
@@@ -103,7 -103,7 +103,7 @@@ static void check_syscall_restart(struc
  static void do_signal(struct task_struct *tsk)
  {
        sigset_t *oldset = sigmask_to_save();
 -      struct ksignal ksig;
 +      struct ksignal ksig = { .sig = 0 };
        int ret;
        int is32 = is_32bit_task();
  
@@@ -153,6 -153,9 +153,9 @@@ void do_notify_resume(struct pt_regs *r
        if (thread_info_flags & _TIF_UPROBE)
                uprobe_notify_resume(regs);
  
+       if (thread_info_flags & _TIF_PATCH_PENDING)
+               klp_update_patch_state(current);
        if (thread_info_flags & _TIF_SIGPENDING) {
                BUG_ON(regs != current->thread.regs);
                do_signal(current);
                tracehook_notify_resume(regs);
        }
  
-       if (thread_info_flags & _TIF_PATCH_PENDING)
-               klp_update_patch_state(current);
        user_enter();
  }
  
diff --combined kernel/signal.c
index e549174c0831374be6ddf7af6ea5b4907a9ae90c,186143b06d0015aa9bb5b1c69759127fafa7b268..c6e4c83dc090ab1361ee9c229f8ff185295c2f46
@@@ -40,6 -40,7 +40,7 @@@
  #include <linux/cn_proc.h>
  #include <linux/compiler.h>
  #include <linux/posix-timers.h>
+ #include <linux/livepatch.h>
  
  #define CREATE_TRACE_POINTS
  #include <trace/events/signal.h>
@@@ -78,7 -79,7 +79,7 @@@ static int sig_task_ignored(struct task
        handler = sig_handler(t, sig);
  
        if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) &&
 -                      handler == SIG_DFL && !force)
 +          handler == SIG_DFL && !(force && sig_kernel_only(sig)))
                return 1;
  
        return sig_handler_ignored(handler, sig);
@@@ -94,15 -95,13 +95,15 @@@ static int sig_ignored(struct task_stru
        if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig))
                return 0;
  
 -      if (!sig_task_ignored(t, sig, force))
 -              return 0;
 -
        /*
 -       * Tracers may want to know about even ignored signals.
 +       * Tracers may want to know about even ignored signal unless it
 +       * is SIGKILL which can't be reported anyway but can be ignored
 +       * by SIGNAL_UNKILLABLE task.
         */
 -      return !t->ptrace;
 +      if (t->ptrace && sig != SIGKILL)
 +              return 0;
 +
 +      return sig_task_ignored(t, sig, force);
  }
  
  /*
@@@ -165,7 -164,8 +166,8 @@@ void recalc_sigpending_and_wake(struct 
  
  void recalc_sigpending(void)
  {
-       if (!recalc_sigpending_tsk(current) && !freezing(current))
+       if (!recalc_sigpending_tsk(current) && !freezing(current) &&
+           !klp_patch_pending(current))
                clear_thread_flag(TIF_SIGPENDING);
  
  }
@@@ -549,7 -549,6 +551,7 @@@ still_pending
                 * a fast-pathed signal or we must have been
                 * out of queue space.  So zero out the info.
                 */
 +              clear_siginfo(info);
                info->si_signo = sig;
                info->si_errno = 0;
                info->si_code = SI_USER;
@@@ -643,9 -642,6 +645,9 @@@ int dequeue_signal(struct task_struct *
                spin_unlock(&tsk->sighand->siglock);
                posixtimer_rearm(info);
                spin_lock(&tsk->sighand->siglock);
 +
 +              /* Don't expose the si_sys_private value to userspace */
 +              info->si_sys_private = 0;
        }
  #endif
        return signr;
@@@ -935,9 -931,9 +937,9 @@@ static void complete_signal(int sig, st
         * then start taking the whole group down immediately.
         */
        if (sig_fatal(p, sig) &&
 -          !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) &&
 +          !(signal->flags & SIGNAL_GROUP_EXIT) &&
            !sigismember(&t->real_blocked, sig) &&
 -          (sig == SIGKILL || !t->ptrace)) {
 +          (sig == SIGKILL || !p->ptrace)) {
                /*
                 * This signal will be fatal to the whole group.
                 */
@@@ -1042,12 -1038,12 +1044,12 @@@ static int __send_signal(int sig, struc
        else
                override_rlimit = 0;
  
 -      q = __sigqueue_alloc(sig, t, GFP_ATOMIC | __GFP_NOTRACK_FALSE_POSITIVE,
 -              override_rlimit);
 +      q = __sigqueue_alloc(sig, t, GFP_ATOMIC, override_rlimit);
        if (q) {
                list_add_tail(&q->list, &pending->list);
                switch ((unsigned long) info) {
                case (unsigned long) SEND_SIG_NOINFO:
 +                      clear_siginfo(&q->info);
                        q->info.si_signo = sig;
                        q->info.si_errno = 0;
                        q->info.si_code = SI_USER;
                        q->info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
                        break;
                case (unsigned long) SEND_SIG_PRIV:
 +                      clear_siginfo(&q->info);
                        q->info.si_signo = sig;
                        q->info.si_errno = 0;
                        q->info.si_code = SI_KERNEL;
@@@ -1491,129 -1486,6 +1493,129 @@@ force_sigsegv(int sig, struct task_stru
        return 0;
  }
  
 +int force_sig_fault(int sig, int code, void __user *addr
 +      ___ARCH_SI_TRAPNO(int trapno)
 +      ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)
 +      , struct task_struct *t)
 +{
 +      struct siginfo info;
 +
 +      clear_siginfo(&info);
 +      info.si_signo = sig;
 +      info.si_errno = 0;
 +      info.si_code  = code;
 +      info.si_addr  = addr;
 +#ifdef __ARCH_SI_TRAPNO
 +      info.si_trapno = trapno;
 +#endif
 +#ifdef __ia64__
 +      info.si_imm = imm;
 +      info.si_flags = flags;
 +      info.si_isr = isr;
 +#endif
 +      return force_sig_info(info.si_signo, &info, t);
 +}
 +
 +int send_sig_fault(int sig, int code, void __user *addr
 +      ___ARCH_SI_TRAPNO(int trapno)
 +      ___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)
 +      , struct task_struct *t)
 +{
 +      struct siginfo info;
 +
 +      clear_siginfo(&info);
 +      info.si_signo = sig;
 +      info.si_errno = 0;
 +      info.si_code  = code;
 +      info.si_addr  = addr;
 +#ifdef __ARCH_SI_TRAPNO
 +      info.si_trapno = trapno;
 +#endif
 +#ifdef __ia64__
 +      info.si_imm = imm;
 +      info.si_flags = flags;
 +      info.si_isr = isr;
 +#endif
 +      return send_sig_info(info.si_signo, &info, t);
 +}
 +
 +#if defined(BUS_MCEERR_AO) && defined(BUS_MCEERR_AR)
 +int force_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct *t)
 +{
 +      struct siginfo info;
 +
 +      WARN_ON((code != BUS_MCEERR_AO) && (code != BUS_MCEERR_AR));
 +      clear_siginfo(&info);
 +      info.si_signo = SIGBUS;
 +      info.si_errno = 0;
 +      info.si_code = code;
 +      info.si_addr = addr;
 +      info.si_addr_lsb = lsb;
 +      return force_sig_info(info.si_signo, &info, t);
 +}
 +
 +int send_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct *t)
 +{
 +      struct siginfo info;
 +
 +      WARN_ON((code != BUS_MCEERR_AO) && (code != BUS_MCEERR_AR));
 +      clear_siginfo(&info);
 +      info.si_signo = SIGBUS;
 +      info.si_errno = 0;
 +      info.si_code = code;
 +      info.si_addr = addr;
 +      info.si_addr_lsb = lsb;
 +      return send_sig_info(info.si_signo, &info, t);
 +}
 +EXPORT_SYMBOL(send_sig_mceerr);
 +#endif
 +
 +#ifdef SEGV_BNDERR
 +int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper)
 +{
 +      struct siginfo info;
 +
 +      clear_siginfo(&info);
 +      info.si_signo = SIGSEGV;
 +      info.si_errno = 0;
 +      info.si_code  = SEGV_BNDERR;
 +      info.si_addr  = addr;
 +      info.si_lower = lower;
 +      info.si_upper = upper;
 +      return force_sig_info(info.si_signo, &info, current);
 +}
 +#endif
 +
 +#ifdef SEGV_PKUERR
 +int force_sig_pkuerr(void __user *addr, u32 pkey)
 +{
 +      struct siginfo info;
 +
 +      clear_siginfo(&info);
 +      info.si_signo = SIGSEGV;
 +      info.si_errno = 0;
 +      info.si_code  = SEGV_PKUERR;
 +      info.si_addr  = addr;
 +      info.si_pkey  = pkey;
 +      return force_sig_info(info.si_signo, &info, current);
 +}
 +#endif
 +
 +/* For the crazy architectures that include trap information in
 + * the errno field, instead of an actual errno value.
 + */
 +int force_sig_ptrace_errno_trap(int errno, void __user *addr)
 +{
 +      struct siginfo info;
 +
 +      clear_siginfo(&info);
 +      info.si_signo = SIGTRAP;
 +      info.si_errno = errno;
 +      info.si_code  = TRAP_HWBKPT;
 +      info.si_addr  = addr;
 +      return force_sig_info(info.si_signo, &info, current);
 +}
 +
  int kill_pgrp(struct pid *pid, int sig, int priv)
  {
        int ret;
@@@ -1752,7 -1624,6 +1754,7 @@@ bool do_notify_parent(struct task_struc
                        sig = SIGCHLD;
        }
  
 +      clear_siginfo(&info);
        info.si_signo = sig;
        info.si_errno = 0;
        /*
@@@ -1847,7 -1718,6 +1849,7 @@@ static void do_notify_parent_cldstop(st
                parent = tsk->real_parent;
        }
  
 +      clear_siginfo(&info);
        info.si_signo = SIGCHLD;
        info.si_errno = 0;
        /*
@@@ -2060,7 -1930,7 +2062,7 @@@ static void ptrace_do_notify(int signr
  {
        siginfo_t info;
  
 -      memset(&info, 0, sizeof info);
 +      clear_siginfo(&info);
        info.si_signo = signr;
        info.si_code = exit_code;
        info.si_pid = task_pid_vnr(current);
@@@ -2267,7 -2137,6 +2269,7 @@@ static int ptrace_signal(int signr, sig
         * have updated *info via PTRACE_SETSIGINFO.
         */
        if (signr != info->si_signo) {
 +              clear_siginfo(info);
                info->si_signo = signr;
                info->si_errno = 0;
                info->si_code = SI_USER;
@@@ -2733,6 -2602,7 +2735,6 @@@ SYSCALL_DEFINE4(rt_sigprocmask, int, ho
  COMPAT_SYSCALL_DEFINE4(rt_sigprocmask, int, how, compat_sigset_t __user *, nset,
                compat_sigset_t __user *, oset, compat_size_t, sigsetsize)
  {
 -#ifdef __BIG_ENDIAN
        sigset_t old_set = current->blocked;
  
        /* XXX: Don't preclude handling different sized sigset_t's.  */
                return -EINVAL;
  
        if (nset) {
 -              compat_sigset_t new32;
                sigset_t new_set;
                int error;
 -              if (copy_from_user(&new32, nset, sizeof(compat_sigset_t)))
 +              if (get_compat_sigset(&new_set, nset))
                        return -EFAULT;
 -
 -              sigset_from_compat(&new_set, &new32);
                sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP));
  
                error = sigprocmask(how, &new_set, NULL);
                if (error)
                        return error;
        }
 -      if (oset) {
 -              compat_sigset_t old32;
 -              sigset_to_compat(&old32, &old_set);
 -              if (copy_to_user(oset, &old32, sizeof(compat_sigset_t)))
 -                      return -EFAULT;
 -      }
 -      return 0;
 -#else
 -      return sys_rt_sigprocmask(how, (sigset_t __user *)nset,
 -                                (sigset_t __user *)oset, sigsetsize);
 -#endif
 +      return oset ? put_compat_sigset(oset, &old_set, sizeof(*oset)) : 0;
  }
  #endif
  
 -static int do_sigpending(void *set, unsigned long sigsetsize)
 +static int do_sigpending(sigset_t *set)
  {
 -      if (sigsetsize > sizeof(sigset_t))
 -              return -EINVAL;
 -
        spin_lock_irq(&current->sighand->siglock);
        sigorsets(set, &current->pending.signal,
                  &current->signal->shared_pending.signal);
  SYSCALL_DEFINE2(rt_sigpending, sigset_t __user *, uset, size_t, sigsetsize)
  {
        sigset_t set;
 -      int err = do_sigpending(&set, sigsetsize);
 +      int err;
 +
 +      if (sigsetsize > sizeof(*uset))
 +              return -EINVAL;
 +
 +      err = do_sigpending(&set);
        if (!err && copy_to_user(uset, &set, sigsetsize))
                err = -EFAULT;
        return err;
  COMPAT_SYSCALL_DEFINE2(rt_sigpending, compat_sigset_t __user *, uset,
                compat_size_t, sigsetsize)
  {
 -#ifdef __BIG_ENDIAN
        sigset_t set;
 -      int err = do_sigpending(&set, sigsetsize);
 -      if (!err) {
 -              compat_sigset_t set32;
 -              sigset_to_compat(&set32, &set);
 -              /* we can get here only if sigsetsize <= sizeof(set) */
 -              if (copy_to_user(uset, &set32, sigsetsize))
 -                      err = -EFAULT;
 -      }
 +      int err;
 +
 +      if (sigsetsize > sizeof(*uset))
 +              return -EINVAL;
 +
 +      err = do_sigpending(&set);
 +      if (!err)
 +              err = put_compat_sigset(uset, &set, sigsetsize);
        return err;
 -#else
 -      return sys_rt_sigpending((sigset_t __user *)uset, sigsetsize);
 -#endif
  }
  #endif
  
@@@ -2820,7 -2705,9 +2822,7 @@@ enum siginfo_layout siginfo_layout(int 
  #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;
  #ifdef FPE_FIXME
                if ((sig == SIGFPE) && (si_code == FPE_FIXME))
                        layout = SIL_FAULT;
 +#endif
 +#ifdef BUS_FIXME
 +              if ((sig == SIGBUS) && (si_code == BUS_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)
  {
        int err;
  #ifdef __ARCH_SI_TRAPNO
                err |= __put_user(from->si_trapno, &to->si_trapno);
  #endif
 -#ifdef BUS_MCEERR_AO
 +#ifdef __ia64__
 +              err |= __put_user(from->si_imm, &to->si_imm);
 +              err |= __put_user(from->si_flags, &to->si_flags);
 +              err |= __put_user(from->si_isr, &to->si_isr);
 +#endif
                /*
                 * Other callers might not initialize the si_lsb field,
                 * so check explicitly for the right codes here.
                 */
 -              if (from->si_signo == SIGBUS &&
 -                  (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO))
 +#ifdef BUS_MCEERR_AR
 +              if (from->si_signo == SIGBUS && from->si_code == BUS_MCEERR_AR)
 +                      err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
 +#endif
 +#ifdef BUS_MCEERR_AO
 +              if (from->si_signo == SIGBUS && from->si_code == BUS_MCEERR_AO)
                        err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
  #endif
  #ifdef SEGV_BNDERR
                err |= __put_user(from->si_uid, &to->si_uid);
                err |= __put_user(from->si_ptr, &to->si_ptr);
                break;
 -#ifdef __ARCH_SIGSYS
        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
        }
        return err;
  }
  
 +#ifdef CONFIG_COMPAT
 +int copy_siginfo_to_user32(struct compat_siginfo __user *to,
 +                         const struct siginfo *from)
 +#if defined(CONFIG_X86_X32_ABI) || defined(CONFIG_IA32_EMULATION)
 +{
 +      return __copy_siginfo_to_user32(to, from, in_x32_syscall());
 +}
 +int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
 +                           const struct siginfo *from, bool x32_ABI)
 +#endif
 +{
 +      struct compat_siginfo new;
 +      memset(&new, 0, sizeof(new));
 +
 +      new.si_signo = from->si_signo;
 +      new.si_errno = from->si_errno;
 +      new.si_code  = from->si_code;
 +      switch(siginfo_layout(from->si_signo, from->si_code)) {
 +      case SIL_KILL:
 +              new.si_pid = from->si_pid;
 +              new.si_uid = from->si_uid;
 +              break;
 +      case SIL_TIMER:
 +              new.si_tid     = from->si_tid;
 +              new.si_overrun = from->si_overrun;
 +              new.si_int     = from->si_int;
 +              break;
 +      case SIL_POLL:
 +              new.si_band = from->si_band;
 +              new.si_fd   = from->si_fd;
 +              break;
 +      case SIL_FAULT:
 +              new.si_addr = ptr_to_compat(from->si_addr);
 +#ifdef __ARCH_SI_TRAPNO
 +              new.si_trapno = from->si_trapno;
 +#endif
 +#ifdef BUS_MCEERR_AR
 +              if ((from->si_signo == SIGBUS) && (from->si_code == BUS_MCEERR_AR))
 +                      new.si_addr_lsb = from->si_addr_lsb;
 +#endif
 +#ifdef BUS_MCEERR_AO
 +              if ((from->si_signo == SIGBUS) && (from->si_code == BUS_MCEERR_AO))
 +                      new.si_addr_lsb = from->si_addr_lsb;
 +#endif
 +#ifdef SEGV_BNDERR
 +              if ((from->si_signo == SIGSEGV) &&
 +                  (from->si_code == SEGV_BNDERR)) {
 +                      new.si_lower = ptr_to_compat(from->si_lower);
 +                      new.si_upper = ptr_to_compat(from->si_upper);
 +              }
 +#endif
 +#ifdef SEGV_PKUERR
 +              if ((from->si_signo == SIGSEGV) &&
 +                  (from->si_code == SEGV_PKUERR))
 +                      new.si_pkey = from->si_pkey;
 +#endif
 +
 +              break;
 +      case SIL_CHLD:
 +              new.si_pid    = from->si_pid;
 +              new.si_uid    = from->si_uid;
 +              new.si_status = from->si_status;
 +#ifdef CONFIG_X86_X32_ABI
 +              if (x32_ABI) {
 +                      new._sifields._sigchld_x32._utime = from->si_utime;
 +                      new._sifields._sigchld_x32._stime = from->si_stime;
 +              } else
  #endif
 +              {
 +                      new.si_utime = from->si_utime;
 +                      new.si_stime = from->si_stime;
 +              }
 +              break;
 +      case SIL_RT:
 +              new.si_pid = from->si_pid;
 +              new.si_uid = from->si_uid;
 +              new.si_int = from->si_int;
 +              break;
 +      case SIL_SYS:
 +              new.si_call_addr = ptr_to_compat(from->si_call_addr);
 +              new.si_syscall   = from->si_syscall;
 +              new.si_arch      = from->si_arch;
 +              break;
 +      }
 +
 +      if (copy_to_user(to, &new, sizeof(struct compat_siginfo)))
 +              return -EFAULT;
 +
 +      return 0;
 +}
 +
 +int copy_siginfo_from_user32(struct siginfo *to,
 +                           const struct compat_siginfo __user *ufrom)
 +{
 +      struct compat_siginfo from;
 +
 +      if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo)))
 +              return -EFAULT;
 +
 +      clear_siginfo(to);
 +      to->si_signo = from.si_signo;
 +      to->si_errno = from.si_errno;
 +      to->si_code  = from.si_code;
 +      switch(siginfo_layout(from.si_signo, from.si_code)) {
 +      case SIL_KILL:
 +              to->si_pid = from.si_pid;
 +              to->si_uid = from.si_uid;
 +              break;
 +      case SIL_TIMER:
 +              to->si_tid     = from.si_tid;
 +              to->si_overrun = from.si_overrun;
 +              to->si_int     = from.si_int;
 +              break;
 +      case SIL_POLL:
 +              to->si_band = from.si_band;
 +              to->si_fd   = from.si_fd;
 +              break;
 +      case SIL_FAULT:
 +              to->si_addr = compat_ptr(from.si_addr);
 +#ifdef __ARCH_SI_TRAPNO
 +              to->si_trapno = from.si_trapno;
 +#endif
 +#ifdef BUS_MCEERR_AR
 +              if ((from.si_signo == SIGBUS) && (from.si_code == BUS_MCEERR_AR))
 +                      to->si_addr_lsb = from.si_addr_lsb;
 +#endif
 +#ifdef BUS_MCEER_AO
 +              if ((from.si_signo == SIGBUS) && (from.si_code == BUS_MCEERR_AO))
 +                      to->si_addr_lsb = from.si_addr_lsb;
 +#endif
 +#ifdef SEGV_BNDERR
 +              if ((from.si_signo == SIGSEGV) && (from.si_code == SEGV_BNDERR)) {
 +                      to->si_lower = compat_ptr(from.si_lower);
 +                      to->si_upper = compat_ptr(from.si_upper);
 +              }
 +#endif
 +#ifdef SEGV_PKUERR
 +              if ((from.si_signo == SIGSEGV) && (from.si_code == SEGV_PKUERR))
 +                      to->si_pkey = from.si_pkey;
 +#endif
 +              break;
 +      case SIL_CHLD:
 +              to->si_pid    = from.si_pid;
 +              to->si_uid    = from.si_uid;
 +              to->si_status = from.si_status;
 +#ifdef CONFIG_X86_X32_ABI
 +              if (in_x32_syscall()) {
 +                      to->si_utime = from._sifields._sigchld_x32._utime;
 +                      to->si_stime = from._sifields._sigchld_x32._stime;
 +              } else
 +#endif
 +              {
 +                      to->si_utime = from.si_utime;
 +                      to->si_stime = from.si_stime;
 +              }
 +              break;
 +      case SIL_RT:
 +              to->si_pid = from.si_pid;
 +              to->si_uid = from.si_uid;
 +              to->si_int = from.si_int;
 +              break;
 +      case SIL_SYS:
 +              to->si_call_addr = compat_ptr(from.si_call_addr);
 +              to->si_syscall   = from.si_syscall;
 +              to->si_arch      = from.si_arch;
 +              break;
 +      }
 +      return 0;
 +}
 +#endif /* CONFIG_COMPAT */
  
  /**
   *  do_sigtimedwait - wait for queued signals specified in @which
@@@ -3208,6 -2918,7 +3210,6 @@@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait
                struct compat_siginfo __user *, uinfo,
                struct compat_timespec __user *, uts, compat_size_t, sigsetsize)
  {
 -      compat_sigset_t s32;
        sigset_t s;
        struct timespec t;
        siginfo_t info;
        if (sigsetsize != sizeof(sigset_t))
                return -EINVAL;
  
 -      if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))
 +      if (get_compat_sigset(&s, uthese))
                return -EFAULT;
 -      sigset_from_compat(&s, &s32);
  
        if (uts) {
                if (compat_get_timespec(&t, uts))
@@@ -3244,7 -2956,6 +3246,7 @@@ SYSCALL_DEFINE2(kill, pid_t, pid, int, 
  {
        struct siginfo info;
  
 +      clear_siginfo(&info);
        info.si_signo = sig;
        info.si_errno = 0;
        info.si_code = SI_USER;
@@@ -3286,9 -2997,8 +3288,9 @@@ do_send_specific(pid_t tgid, pid_t pid
  
  static int do_tkill(pid_t tgid, pid_t pid, int sig)
  {
 -      struct siginfo info = {};
 +      struct siginfo info;
  
 +      clear_siginfo(&info);
        info.si_signo = sig;
        info.si_errno = 0;
        info.si_code = SI_TKILL;
@@@ -3369,7 -3079,7 +3371,7 @@@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo
                        int, sig,
                        struct compat_siginfo __user *, uinfo)
  {
 -      siginfo_t info = {};
 +      siginfo_t info;
        int ret = copy_siginfo_from_user32(&info, uinfo);
        if (unlikely(ret))
                return ret;
@@@ -3413,7 -3123,7 +3415,7 @@@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinf
                        int, sig,
                        struct compat_siginfo __user *, uinfo)
  {
 -      siginfo_t info = {};
 +      siginfo_t info;
  
        if (copy_siginfo_from_user32(&info, uinfo))
                return -EFAULT;
@@@ -3637,11 -3347,15 +3639,11 @@@ SYSCALL_DEFINE1(sigpending, old_sigset_
  #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(set.sig[0]));
 +      int err = do_sigpending(&set);
        if (!err)
                err = put_user(set.sig[0], set32);
        return err;
 -#else
 -      return sys_rt_sigpending((sigset_t __user *)set32, sizeof(*set32));
 -#endif
  }
  #endif
  
@@@ -3739,6 -3453,7 +3741,6 @@@ COMPAT_SYSCALL_DEFINE4(rt_sigaction, in
                compat_size_t, sigsetsize)
  {
        struct k_sigaction new_ka, old_ka;
 -      compat_sigset_t mask;
  #ifdef __ARCH_HAS_SA_RESTORER
        compat_uptr_t restorer;
  #endif
                ret |= get_user(restorer, &act->sa_restorer);
                new_ka.sa.sa_restorer = compat_ptr(restorer);
  #endif
 -              ret |= copy_from_user(&mask, &act->sa_mask, sizeof(mask));
 +              ret |= get_compat_sigset(&new_ka.sa.sa_mask, &act->sa_mask);
                ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags);
                if (ret)
                        return -EFAULT;
 -              sigset_from_compat(&new_ka.sa.sa_mask, &mask);
        }
  
        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
        if (!ret && oact) {
 -              sigset_to_compat(&mask, &old_ka.sa.sa_mask);
                ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), 
                               &oact->sa_handler);
 -              ret |= copy_to_user(&oact->sa_mask, &mask, sizeof(mask));
 +              ret |= put_compat_sigset(&oact->sa_mask, &old_ka.sa.sa_mask,
 +                                       sizeof(oact->sa_mask));
                ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags);
  #ifdef __ARCH_HAS_SA_RESTORER
                ret |= put_user(ptr_to_compat(old_ka.sa.sa_restorer),
@@@ -3947,15 -3663,22 +3949,15 @@@ SYSCALL_DEFINE2(rt_sigsuspend, sigset_
  #ifdef CONFIG_COMPAT
  COMPAT_SYSCALL_DEFINE2(rt_sigsuspend, compat_sigset_t __user *, unewset, compat_size_t, sigsetsize)
  {
 -#ifdef __BIG_ENDIAN
        sigset_t newset;
 -      compat_sigset_t newset32;
  
        /* XXX: Don't preclude handling different sized sigset_t's.  */
        if (sigsetsize != sizeof(sigset_t))
                return -EINVAL;
  
 -      if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t)))
 +      if (get_compat_sigset(&newset, unewset))
                return -EFAULT;
 -      sigset_from_compat(&newset, &newset32);
        return sigsuspend(&newset);
 -#else
 -      /* on little-endian bitmaps don't care about granularity */
 -      return sys_rt_sigsuspend((sigset_t __user *)unewset, sigsetsize);
 -#endif
  }
  #endif
  
@@@ -3986,7 -3709,6 +3988,7 @@@ void __init signals_init(void
        /* If this check fails, the __ARCH_SI_PREAMBLE_SIZE value is wrong! */
        BUILD_BUG_ON(__ARCH_SI_PREAMBLE_SIZE
                != offsetof(struct siginfo, _sifields._pad));
 +      BUILD_BUG_ON(sizeof(struct siginfo) != SI_MAX_SIZE);
  
        sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC);
  }
  #ifdef CONFIG_KGDB_KDB
  #include <linux/kdb.h>
  /*
 - * kdb_send_sig_info - Allows kdb to send signals without exposing
 + * kdb_send_sig - Allows kdb to send signals without exposing
   * signal internals.  This function checks if the required locks are
   * available before calling the main signal code, to avoid kdb
   * deadlocks.
   */
 -void
 -kdb_send_sig_info(struct task_struct *t, struct siginfo *info)
 +void kdb_send_sig(struct task_struct *t, int sig)
  {
        static struct task_struct *kdb_prev_t;
 -      int sig, new_t;
 +      int new_t, ret;
        if (!spin_trylock(&t->sighand->siglock)) {
                kdb_printf("Can't do kill command now.\n"
                           "The sigmask lock is held somewhere else in "
                           "kernel, try again later\n");
                return;
        }
 -      spin_unlock(&t->sighand->siglock);
        new_t = kdb_prev_t != t;
        kdb_prev_t = t;
        if (t->state != TASK_RUNNING && new_t) {
 +              spin_unlock(&t->sighand->siglock);
                kdb_printf("Process is not RUNNING, sending a signal from "
                           "kdb risks deadlock\n"
                           "on the run queue locks. "
                           "the deadlock.\n");
                return;
        }
 -      sig = info->si_signo;
 -      if (send_sig_info(sig, info, t))
 +      ret = send_signal(sig, SEND_SIG_PRIV, t, false);
 +      spin_unlock(&t->sighand->siglock);
 +      if (ret)
                kdb_printf("Fail to deliver Signal %d to process %d.\n",
                           sig, t->pid);
        else