From 4181d22596f61d060139bb114724f89b3ad28c8d Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 15 Apr 2018 19:40:02 -0500 Subject: signal: Remove ifdefs for BUS_MCEERR_AR and BUS_MCEERR_AO With the recent architecture cleanups these si_codes are always defined so there is no need to test for them. Signed-off-by: "Eric W. Biederman" --- fs/signalfd.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'fs') diff --git a/fs/signalfd.c b/fs/signalfd.c index d2187a813376c..ff302bf50be4d 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -117,26 +117,15 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, #ifdef __ARCH_SI_TRAPNO err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno); #endif -#ifdef BUS_MCEERR_AO /* * 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_AO) + ((kinfo->si_code == BUS_MCEERR_AR) || + (kinfo->si_code == BUS_MCEERR_AO))) err |= __put_user((short) kinfo->si_addr_lsb, &uinfo->ssi_addr_lsb); -#endif -#ifdef BUS_MCEERR_AR - /* - * 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) - err |= __put_user((short) kinfo->si_addr_lsb, - &uinfo->ssi_addr_lsb); -#endif break; case SIL_CHLD: err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); -- cgit v1.2.3 From 5611f55ee4df70d947bf239c587e742efdab028b Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 24 Apr 2018 20:39:16 -0500 Subject: signal/signalfd: Remove __put_user from signalfd_copyinfo Put a signalfd_siginfo structure on the stack fully initializae it and then copy it to userspace. The code is a little less wordy, and this avoids a long series of the somewhat costly __put_user calls. Signed-off-by: "Eric W. Biederman" --- fs/signalfd.c | 56 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 27 deletions(-) (limited to 'fs') diff --git a/fs/signalfd.c b/fs/signalfd.c index ff302bf50be4d..31e960209a084 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -81,41 +81,41 @@ static __poll_t signalfd_poll(struct file *file, poll_table *wait) static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, siginfo_t const *kinfo) { - long err; + struct signalfd_siginfo new; BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128); /* * Unused members should be zero ... */ - err = __clear_user(uinfo, sizeof(*uinfo)); + memset(&new, 0, sizeof(new)); /* * If you change siginfo_t structure, please be sure * this code is fixed accordingly. */ - err |= __put_user(kinfo->si_signo, &uinfo->ssi_signo); - err |= __put_user(kinfo->si_errno, &uinfo->ssi_errno); - err |= __put_user(kinfo->si_code, &uinfo->ssi_code); + new.ssi_signo = kinfo->si_signo; + new.ssi_errno = kinfo->si_errno; + new.ssi_code = kinfo->si_code; switch (siginfo_layout(kinfo->si_signo, kinfo->si_code)) { case SIL_KILL: - err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); - err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); + new.ssi_pid = kinfo->si_pid; + new.ssi_uid = kinfo->si_uid; break; case SIL_TIMER: - err |= __put_user(kinfo->si_tid, &uinfo->ssi_tid); - err |= __put_user(kinfo->si_overrun, &uinfo->ssi_overrun); - err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); - err |= __put_user(kinfo->si_int, &uinfo->ssi_int); + new.ssi_tid = kinfo->si_tid; + new.ssi_overrun = kinfo->si_overrun; + new.ssi_ptr = (long) kinfo->si_ptr; + new.ssi_int = kinfo->si_int; break; case SIL_POLL: - err |= __put_user(kinfo->si_band, &uinfo->ssi_band); - err |= __put_user(kinfo->si_fd, &uinfo->ssi_fd); + new.ssi_band = kinfo->si_band; + new.ssi_fd = kinfo->si_fd; break; case SIL_FAULT: - err |= __put_user((long) kinfo->si_addr, &uinfo->ssi_addr); + new.ssi_addr = (long) kinfo->si_addr; #ifdef __ARCH_SI_TRAPNO - err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno); + new.ssi_trapno = kinfo->si_trapno; #endif /* * Other callers might not initialize the si_lsb field, @@ -124,29 +124,31 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, if (kinfo->si_signo == SIGBUS && ((kinfo->si_code == BUS_MCEERR_AR) || (kinfo->si_code == BUS_MCEERR_AO))) - err |= __put_user((short) kinfo->si_addr_lsb, - &uinfo->ssi_addr_lsb); + new.ssi_addr_lsb = (short) kinfo->si_addr_lsb; break; case SIL_CHLD: - err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); - err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); - err |= __put_user(kinfo->si_status, &uinfo->ssi_status); - err |= __put_user(kinfo->si_utime, &uinfo->ssi_utime); - err |= __put_user(kinfo->si_stime, &uinfo->ssi_stime); + new.ssi_pid = kinfo->si_pid; + new.ssi_uid = kinfo->si_uid; + new.ssi_status = kinfo->si_status; + new.ssi_utime = kinfo->si_utime; + new.ssi_stime = kinfo->si_stime; break; case SIL_RT: default: /* * This case catches also the signals queued by sigqueue(). */ - err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); - err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); - err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); - err |= __put_user(kinfo->si_int, &uinfo->ssi_int); + new.ssi_pid = kinfo->si_pid; + new.ssi_uid = kinfo->si_uid; + new.ssi_ptr = (long) kinfo->si_ptr; + new.ssi_int = kinfo->si_int; break; } - return err ? -EFAULT: sizeof(*uinfo); + if (copy_to_user(uinfo, &new, sizeof(struct signalfd_siginfo))) + return -EFAULT; + + return sizeof(*uinfo); } static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, siginfo_t *info, -- cgit v1.2.3 From 76b7f670730e87974f71df9f6129811e2769666e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 24 Apr 2018 20:48:32 -0500 Subject: signal/signalfd: Add support for SIGSYS I don't know why signalfd has never grown support for SIGSYS but grow it now. This corrects an oversight and removes a need for a default in the switch statement. Allowing gcc to warn when future members are added to the enum siginfo_layout, and signalfd does not handle them. Signed-off-by: "Eric W. Biederman" --- fs/signalfd.c | 6 +++++- include/uapi/linux/signalfd.h | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/signalfd.c b/fs/signalfd.c index 31e960209a084..f652249f59f99 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -134,7 +134,6 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, new.ssi_stime = kinfo->si_stime; break; case SIL_RT: - default: /* * This case catches also the signals queued by sigqueue(). */ @@ -143,6 +142,11 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, new.ssi_ptr = (long) kinfo->si_ptr; new.ssi_int = kinfo->si_int; break; + case SIL_SYS: + new.ssi_call_addr = (long) kinfo->si_call_addr; + new.ssi_syscall = kinfo->si_syscall; + new.ssi_arch = kinfo->si_arch; + break; } if (copy_to_user(uinfo, &new, sizeof(struct signalfd_siginfo))) diff --git a/include/uapi/linux/signalfd.h b/include/uapi/linux/signalfd.h index 6f0da42fc5ef3..83429a05b698e 100644 --- a/include/uapi/linux/signalfd.h +++ b/include/uapi/linux/signalfd.h @@ -35,6 +35,10 @@ struct signalfd_siginfo { __u64 ssi_stime; __u64 ssi_addr; __u16 ssi_addr_lsb; + __u16 __pad2; + __s32 ssi_syscall; + __u64 ssi_call_addr; + __u32 ssi_arch; /* * Pad strcture to 128 bytes. Remember to update the @@ -45,7 +49,7 @@ struct signalfd_siginfo { * comes out of a read(2) and we really don't want to have * a compat on read(2). */ - __u8 __pad[46]; + __u8 __pad[28]; }; -- cgit v1.2.3 From 31931c93dfe05a76385a443ed28244a50e915a46 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 24 Apr 2018 20:59:47 -0500 Subject: 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" --- fs/signalfd.c | 24 ++++++++++----- include/linux/signal.h | 3 ++ kernel/signal.c | 81 ++++++++++++++++++++++++++++++++++---------------- 3 files changed, 75 insertions(+), 33 deletions(-) (limited to 'fs') diff --git a/fs/signalfd.c b/fs/signalfd.c index f652249f59f99..cbb42f77a2bd2 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -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; diff --git a/include/linux/signal.h b/include/linux/signal.h index a9bc7e1b077e0..3c5200137b24f 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -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, diff --git a/kernel/signal.c b/kernel/signal.c index 376b42f26e6d4..8a85da8aaa7ca 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -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; -- cgit v1.2.3