signal: Extend siginfo_layout with SIL_FAULT_{MCEERR|BNDERR|PKUERR}
authorEric W. Biederman <ebiederm@xmission.com>
Wed, 25 Apr 2018 01:59:47 +0000 (20:59 -0500)
committerEric W. Biederman <ebiederm@xmission.com>
Fri, 27 Apr 2018 00:51:14 +0000 (19:51 -0500)
Update the siginfo_layout function and enum siginfo_layout to represent
all of the possible field layouts of struct siginfo.

This allows the uses of siginfo_layout in um and arm64 where they are testing
for SIL_FAULT to be more accurate as this rules out the other cases.

Further this allows the switch statements on siginfo_layout to be simpler
if perhaps a little more wordy.  Making it easier to understand what is
actually going on.

As SIL_FAULT_BNDERR and SIL_FAULT_PKUERR are never expected to appear
in signalfd just treat them as SIL_FAULT.  To include them would take
20 extra bytes an pretty much fill up what is left of
signalfd_siginfo.

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
fs/signalfd.c
include/linux/signal.h
kernel/signal.c

index f652249f59f99e5cf413cf42972c818a586d3352..cbb42f77a2bd221d8ab7c9cb2b6dc0e047b321e2 100644 (file)
@@ -112,19 +112,27 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
                new.ssi_band = kinfo->si_band;
                new.ssi_fd   = kinfo->si_fd;
                break;
+       case SIL_FAULT_BNDERR:
+       case SIL_FAULT_PKUERR:
+               /*
+                * 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.
+                */
        case SIL_FAULT:
                new.ssi_addr = (long) kinfo->si_addr;
 #ifdef __ARCH_SI_TRAPNO
                new.ssi_trapno = kinfo->si_trapno;
 #endif
-               /*
-                * 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) ||
-                    (kinfo->si_code == BUS_MCEERR_AO)))
-                       new.ssi_addr_lsb = (short) kinfo->si_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:
                new.ssi_pid    = kinfo->si_pid;
index a9bc7e1b077e0784c209d134601b8884b833a9d9..3c5200137b24f67725997532af950ffb5daf8fdf 100644 (file)
@@ -28,6 +28,9 @@ enum siginfo_layout {
        SIL_TIMER,
        SIL_POLL,
        SIL_FAULT,
+       SIL_FAULT_MCEERR,
+       SIL_FAULT_BNDERR,
+       SIL_FAULT_PKUERR,
        SIL_CHLD,
        SIL_RT,
        SIL_SYS,
index 376b42f26e6d432bef26bf54100c1d632fec52ea..8a85da8aaa7ca10f33720042bbf169f6bf4003d7 100644 (file)
@@ -2820,8 +2820,19 @@ enum siginfo_layout siginfo_layout(int sig, int si_code)
                        [SIGPOLL] = { NSIGPOLL, SIL_POLL },
                        [SIGSYS]  = { NSIGSYS,  SIL_SYS },
                };
-               if ((sig < ARRAY_SIZE(filter)) && (si_code <= filter[sig].limit))
+               if ((sig < ARRAY_SIZE(filter)) && (si_code <= filter[sig].limit)) {
                        layout = filter[sig].layout;
+                       /* Handle the exceptions */
+                       if ((sig == SIGBUS) &&
+                           (si_code >= BUS_MCEERR_AR) && (si_code <= BUS_MCEERR_AO))
+                               layout = SIL_FAULT_MCEERR;
+                       else if ((sig == SIGSEGV) && (si_code == SEGV_BNDERR))
+                               layout = SIL_FAULT_BNDERR;
+#ifdef SEGV_PKUERR
+                       else if ((sig == SIGSEGV) && (si_code == SEGV_PKUERR))
+                               layout = SIL_FAULT_PKUERR;
+#endif
+               }
                else if (si_code <= NSIGPOLL)
                        layout = SIL_POLL;
        } else {
@@ -2878,19 +2889,28 @@ int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
 #ifdef __ARCH_SI_TRAPNO
                new.si_trapno = from->si_trapno;
 #endif
-               if ((from->si_signo == SIGBUS) &&
-                   ((from->si_code == BUS_MCEERR_AR) ||
-                    (from->si_code == BUS_MCEERR_AO)))
-                       new.si_addr_lsb = from->si_addr_lsb;
-
-               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);
-               }
-               if ((from->si_signo == SIGSEGV) &&
-                   (from->si_code == SEGV_PKUERR))
-                       new.si_pkey = from->si_pkey;
+               break;
+       case SIL_FAULT_MCEERR:
+               new.si_addr = ptr_to_compat(from->si_addr);
+#ifdef __ARCH_SI_TRAPNO
+               new.si_trapno = from->si_trapno;
+#endif
+               new.si_addr_lsb = from->si_addr_lsb;
+               break;
+       case SIL_FAULT_BNDERR:
+               new.si_addr = ptr_to_compat(from->si_addr);
+#ifdef __ARCH_SI_TRAPNO
+               new.si_trapno = from->si_trapno;
+#endif
+               new.si_lower = ptr_to_compat(from->si_lower);
+               new.si_upper = ptr_to_compat(from->si_upper);
+               break;
+       case SIL_FAULT_PKUERR:
+               new.si_addr = ptr_to_compat(from->si_addr);
+#ifdef __ARCH_SI_TRAPNO
+               new.si_trapno = from->si_trapno;
+#endif
+               new.si_pkey = from->si_pkey;
                break;
        case SIL_CHLD:
                new.si_pid    = from->si_pid;
@@ -2956,17 +2976,28 @@ int copy_siginfo_from_user32(struct siginfo *to,
 #ifdef __ARCH_SI_TRAPNO
                to->si_trapno = from.si_trapno;
 #endif
-               if ((from.si_signo == SIGBUS) &&
-                   ((from.si_code == BUS_MCEERR_AR) ||
-                    (from.si_code == BUS_MCEERR_AO)))
-                       to->si_addr_lsb = from.si_addr_lsb;
-
-               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);
-               }
-               if ((from.si_signo == SIGSEGV) && (from.si_code == SEGV_PKUERR))
-                       to->si_pkey = from.si_pkey;
+               break;
+       case SIL_FAULT_MCEERR:
+               to->si_addr = compat_ptr(from.si_addr);
+#ifdef __ARCH_SI_TRAPNO
+               to->si_trapno = from.si_trapno;
+#endif
+               to->si_addr_lsb = from.si_addr_lsb;
+               break;
+       case SIL_FAULT_BNDERR:
+               to->si_addr = compat_ptr(from.si_addr);
+#ifdef __ARCH_SI_TRAPNO
+               to->si_trapno = from.si_trapno;
+#endif
+               to->si_lower = compat_ptr(from.si_lower);
+               to->si_upper = compat_ptr(from.si_upper);
+               break;
+       case SIL_FAULT_PKUERR:
+               to->si_addr = compat_ptr(from.si_addr);
+#ifdef __ARCH_SI_TRAPNO
+               to->si_trapno = from.si_trapno;
+#endif
+               to->si_pkey = from.si_pkey;
                break;
        case SIL_CHLD:
                to->si_pid    = from.si_pid;