signal: Extend siginfo_layout with SIL_FAULT_{MCEERR|BNDERR|PKUERR}

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>
This commit is contained in:
Eric W. Biederman 2018-04-24 20:59:47 -05:00
parent 36a4ca3d9b
commit 31931c93df
3 changed files with 75 additions and 33 deletions

View File

@ -112,19 +112,27 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
new.ssi_band = kinfo->si_band; new.ssi_band = kinfo->si_band;
new.ssi_fd = kinfo->si_fd; new.ssi_fd = kinfo->si_fd;
break; 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: case SIL_FAULT:
new.ssi_addr = (long) kinfo->si_addr; new.ssi_addr = (long) kinfo->si_addr;
#ifdef __ARCH_SI_TRAPNO #ifdef __ARCH_SI_TRAPNO
new.ssi_trapno = kinfo->si_trapno; new.ssi_trapno = kinfo->si_trapno;
#endif #endif
/* break;
* Other callers might not initialize the si_lsb field, case SIL_FAULT_MCEERR:
* so check explicitly for the right codes here. new.ssi_addr = (long) kinfo->si_addr;
*/ #ifdef __ARCH_SI_TRAPNO
if (kinfo->si_signo == SIGBUS && new.ssi_trapno = kinfo->si_trapno;
((kinfo->si_code == BUS_MCEERR_AR) || #endif
(kinfo->si_code == BUS_MCEERR_AO))) new.ssi_addr_lsb = (short) kinfo->si_addr_lsb;
new.ssi_addr_lsb = (short) kinfo->si_addr_lsb;
break; break;
case SIL_CHLD: case SIL_CHLD:
new.ssi_pid = kinfo->si_pid; new.ssi_pid = kinfo->si_pid;

View File

@ -28,6 +28,9 @@ enum siginfo_layout {
SIL_TIMER, SIL_TIMER,
SIL_POLL, SIL_POLL,
SIL_FAULT, SIL_FAULT,
SIL_FAULT_MCEERR,
SIL_FAULT_BNDERR,
SIL_FAULT_PKUERR,
SIL_CHLD, SIL_CHLD,
SIL_RT, SIL_RT,
SIL_SYS, SIL_SYS,

View File

@ -2820,8 +2820,19 @@ enum siginfo_layout siginfo_layout(int sig, int si_code)
[SIGPOLL] = { NSIGPOLL, SIL_POLL }, [SIGPOLL] = { NSIGPOLL, SIL_POLL },
[SIGSYS] = { NSIGSYS, SIL_SYS }, [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; 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) else if (si_code <= NSIGPOLL)
layout = SIL_POLL; layout = SIL_POLL;
} else { } else {
@ -2878,19 +2889,28 @@ int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
#ifdef __ARCH_SI_TRAPNO #ifdef __ARCH_SI_TRAPNO
new.si_trapno = from->si_trapno; new.si_trapno = from->si_trapno;
#endif #endif
if ((from->si_signo == SIGBUS) && break;
((from->si_code == BUS_MCEERR_AR) || case SIL_FAULT_MCEERR:
(from->si_code == BUS_MCEERR_AO))) new.si_addr = ptr_to_compat(from->si_addr);
new.si_addr_lsb = from->si_addr_lsb; #ifdef __ARCH_SI_TRAPNO
new.si_trapno = from->si_trapno;
if ((from->si_signo == SIGSEGV) && #endif
(from->si_code == SEGV_BNDERR)) { new.si_addr_lsb = from->si_addr_lsb;
new.si_lower = ptr_to_compat(from->si_lower); break;
new.si_upper = ptr_to_compat(from->si_upper); case SIL_FAULT_BNDERR:
} new.si_addr = ptr_to_compat(from->si_addr);
if ((from->si_signo == SIGSEGV) && #ifdef __ARCH_SI_TRAPNO
(from->si_code == SEGV_PKUERR)) new.si_trapno = from->si_trapno;
new.si_pkey = from->si_pkey; #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; break;
case SIL_CHLD: case SIL_CHLD:
new.si_pid = from->si_pid; new.si_pid = from->si_pid;
@ -2956,17 +2976,28 @@ int copy_siginfo_from_user32(struct siginfo *to,
#ifdef __ARCH_SI_TRAPNO #ifdef __ARCH_SI_TRAPNO
to->si_trapno = from.si_trapno; to->si_trapno = from.si_trapno;
#endif #endif
if ((from.si_signo == SIGBUS) && break;
((from.si_code == BUS_MCEERR_AR) || case SIL_FAULT_MCEERR:
(from.si_code == BUS_MCEERR_AO))) to->si_addr = compat_ptr(from.si_addr);
to->si_addr_lsb = from.si_addr_lsb; #ifdef __ARCH_SI_TRAPNO
to->si_trapno = from.si_trapno;
if ((from.si_signo == SIGSEGV) && (from.si_code == SEGV_BNDERR)) { #endif
to->si_lower = compat_ptr(from.si_lower); to->si_addr_lsb = from.si_addr_lsb;
to->si_upper = compat_ptr(from.si_upper); break;
} case SIL_FAULT_BNDERR:
if ((from.si_signo == SIGSEGV) && (from.si_code == SEGV_PKUERR)) to->si_addr = compat_ptr(from.si_addr);
to->si_pkey = from.si_pkey; #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; break;
case SIL_CHLD: case SIL_CHLD:
to->si_pid = from.si_pid; to->si_pid = from.si_pid;