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" <ebiederm@xmission.com>
This commit is contained in:
Eric W. Biederman 2018-04-24 20:39:16 -05:00
parent 9181010565
commit 5611f55ee4

View file

@ -81,41 +81,41 @@ static __poll_t signalfd_poll(struct file *file, poll_table *wait)
static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
siginfo_t const *kinfo) siginfo_t const *kinfo)
{ {
long err; struct signalfd_siginfo new;
BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128); BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128);
/* /*
* Unused members should be zero ... * 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 * If you change siginfo_t structure, please be sure
* this code is fixed accordingly. * this code is fixed accordingly.
*/ */
err |= __put_user(kinfo->si_signo, &uinfo->ssi_signo); new.ssi_signo = kinfo->si_signo;
err |= __put_user(kinfo->si_errno, &uinfo->ssi_errno); new.ssi_errno = kinfo->si_errno;
err |= __put_user(kinfo->si_code, &uinfo->ssi_code); new.ssi_code = kinfo->si_code;
switch (siginfo_layout(kinfo->si_signo, kinfo->si_code)) { switch (siginfo_layout(kinfo->si_signo, kinfo->si_code)) {
case SIL_KILL: case SIL_KILL:
err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); new.ssi_pid = kinfo->si_pid;
err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); new.ssi_uid = kinfo->si_uid;
break; break;
case SIL_TIMER: case SIL_TIMER:
err |= __put_user(kinfo->si_tid, &uinfo->ssi_tid); new.ssi_tid = kinfo->si_tid;
err |= __put_user(kinfo->si_overrun, &uinfo->ssi_overrun); new.ssi_overrun = kinfo->si_overrun;
err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); new.ssi_ptr = (long) kinfo->si_ptr;
err |= __put_user(kinfo->si_int, &uinfo->ssi_int); new.ssi_int = kinfo->si_int;
break; break;
case SIL_POLL: case SIL_POLL:
err |= __put_user(kinfo->si_band, &uinfo->ssi_band); new.ssi_band = kinfo->si_band;
err |= __put_user(kinfo->si_fd, &uinfo->ssi_fd); new.ssi_fd = kinfo->si_fd;
break; break;
case SIL_FAULT: case SIL_FAULT:
err |= __put_user((long) kinfo->si_addr, &uinfo->ssi_addr); new.ssi_addr = (long) kinfo->si_addr;
#ifdef __ARCH_SI_TRAPNO #ifdef __ARCH_SI_TRAPNO
err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno); new.ssi_trapno = kinfo->si_trapno;
#endif #endif
/* /*
* Other callers might not initialize the si_lsb field, * 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 && if (kinfo->si_signo == SIGBUS &&
((kinfo->si_code == BUS_MCEERR_AR) || ((kinfo->si_code == BUS_MCEERR_AR) ||
(kinfo->si_code == BUS_MCEERR_AO))) (kinfo->si_code == BUS_MCEERR_AO)))
err |= __put_user((short) kinfo->si_addr_lsb, new.ssi_addr_lsb = (short) kinfo->si_addr_lsb;
&uinfo->ssi_addr_lsb);
break; break;
case SIL_CHLD: case SIL_CHLD:
err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); new.ssi_pid = kinfo->si_pid;
err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); new.ssi_uid = kinfo->si_uid;
err |= __put_user(kinfo->si_status, &uinfo->ssi_status); new.ssi_status = kinfo->si_status;
err |= __put_user(kinfo->si_utime, &uinfo->ssi_utime); new.ssi_utime = kinfo->si_utime;
err |= __put_user(kinfo->si_stime, &uinfo->ssi_stime); new.ssi_stime = kinfo->si_stime;
break; break;
case SIL_RT: case SIL_RT:
default: default:
/* /*
* This case catches also the signals queued by sigqueue(). * This case catches also the signals queued by sigqueue().
*/ */
err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); new.ssi_pid = kinfo->si_pid;
err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); new.ssi_uid = kinfo->si_uid;
err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); new.ssi_ptr = (long) kinfo->si_ptr;
err |= __put_user(kinfo->si_int, &uinfo->ssi_int); new.ssi_int = kinfo->si_int;
break; 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, static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, siginfo_t *info,