Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/fs/aio.c b/fs/aio.c
- index e8623a5e8736..f86781a9cb79 100644
- --- a/fs/aio.c
- +++ b/fs/aio.c
- @@ -1865,6 +1865,7 @@ static long do_io_getevents(aio_context_t ctx_id,
- * specifies an infinite timeout. Note that the timeout pointed to by
- * timeout is relative. Will fail with -ENOSYS if not implemented.
- */
- +#if defined(CONFIG_COMPAT_32BIT_TIME) || defined(CONFIG_64BIT)
- SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id,
- long, min_nr,
- long, nr,
- @@ -1882,6 +1883,7 @@ SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id,
- ret = -EINTR;
- return ret;
- }
- +#endif
- SYSCALL_DEFINE6(io_pgetevents,
- aio_context_t, ctx_id,
- @@ -1928,6 +1930,52 @@ SYSCALL_DEFINE6(io_pgetevents,
- return ret;
- }
- +#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT)
- +SYSCALL_DEFINE6(io_pgetevents_time32,
- + compat_aio_context_t, ctx_id,
- + long, min_nr,
- + long, nr,
- + struct io_event __user *, events,
- + struct __kernel_old_timespec __user *, timeout,
- + const struct __aio_sigset __user *, usig)
- +{
- + struct __aio_sigset ksig = { NULL, };
- + sigset_t ksigmask, sigsaved;
- + struct timespec64 t;
- + int ret;
- +
- + if (timeout && get_old_timespec(&t, timeout))
- + return -EFAULT;
- +
- + if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
- + return -EFAULT;
- +
- + if (ksig.sigmask) {
- + if (ksig.sigsetsize != sizeof(ksig))
- + return -EINVAL;
- + if (copy_from_user(&ksigmask, ksig.sigmask, sizeof(ksigmask)))
- + return -EFAULT;
- + sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
- + sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
- + }
- +
- + ret = do_io_getevents(ctx_id, min_nr, nr, events, timeout ? &t : NULL);
- + if (signal_pending(current)) {
- + if (ksig.sigmask) {
- + current->saved_sigmask = sigsaved;
- + set_restore_sigmask();
- + }
- + if (!ret)
- + ret = -ERESTARTNOHAND;
- + } else {
- + if (ksig.sigmask)
- + sigprocmask(SIG_SETMASK, &sigsaved, NULL);
- + }
- +
- + return ret;
- +}
- +#endif
- +
- #ifdef CONFIG_COMPAT
- struct __compat_aio_sigset {
- compat_sigset_t __user *sigmask;
- @@ -1977,25 +2025,8 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,
- return ret;
- }
- -#endif
- -
- -#ifdef CONFIG_COMPAT_32BIT_TIME
- -#ifndef CONFIG_COMPAT
- -#define compat_sigset_t sigset_t
- -struct __compat_aio_sigset {
- - compat_sigset_t __user *sigmask;
- - compat_size_t sigsetsize;
- -};
- -
- -static inline int get_compat_sigset(sigset_t *set, const sigset_t __user *compat)
- -{
- - if (copy_from_user(set, compat, sizeof *set))
- - return -EFAULT;
- -
- - return 0;
- -}
- -#endif
- +#if defined(CONFIG_COMPAT_32BIT_TIME)
- COMPAT_SYSCALL_DEFINE5(io_getevents, compat_aio_context_t, ctx_id,
- compat_long_t, min_nr,
- compat_long_t, nr,
- @@ -2057,4 +2088,5 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
- return ret;
- }
- -#endif
- +#endif /* CONFIG_COMPAT_32BIT_TIME */
- +#endif /* CONFIG_COMPAT */
- diff --git a/fs/select.c b/fs/select.c
- index ffea9a4d8dda..24293bd589ee 100644
- --- a/fs/select.c
- +++ b/fs/select.c
- @@ -1095,7 +1095,171 @@ SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds,
- return ret;
- }
- -#if defined(CONFIG_COMPAT_32BIT_TIME) || defined(CONFIG_COMPAT)
- +#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT)
- +static
- +int poll_select_copy_remaining_time32(struct timespec64 *end_time, void __user *p,
- + int timeval, int ret)
- +{
- + struct timespec64 ts;
- +
- + if (!p)
- + return ret;
- +
- + if (current->personality & STICKY_TIMEOUTS)
- + goto sticky;
- +
- + /* No update for zero timeout */
- + if (!end_time->tv_sec && !end_time->tv_nsec)
- + return ret;
- +
- + ktime_get_ts64(&ts);
- + ts = timespec64_sub(*end_time, ts);
- + if (ts.tv_sec < 0)
- + ts.tv_sec = ts.tv_nsec = 0;
- +
- + if (timeval) {
- + struct __kernel_old_timeval rtv;
- +
- + rtv.tv_sec = ts.tv_sec;
- + rtv.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
- +
- + if (!copy_to_user(p, &rtv, sizeof(rtv)))
- + return ret;
- + } else {
- + if (!put_old_timespec(&ts, p))
- + return ret;
- + }
- + /*
- + * If an application puts its timeval in read-only memory, we
- + * don't want the Linux-specific update to the timeval to
- + * cause a fault after the select has completed
- + * successfully. However, because we're not updating the
- + * timeval, we can't restart the system call.
- + */
- +
- +sticky:
- + if (ret == -ERESTARTNOHAND)
- + ret = -EINTR;
- + return ret;
- +}
- +
- +static long do_pselect_time32(int n, fd_set __user *inp,
- + fd_set __user *outp, fd_set __user *exp,
- + struct __kernel_old_timespec __user *tsp,
- + const sigset_t __user *sigmask, size_t sigsetsize)
- +{
- + sigset_t ksigmask, sigsaved;
- + struct timespec64 ts, end_time, *to = NULL;
- + int ret;
- +
- + if (tsp) {
- + if (get_old_timespec(&ts, tsp))
- + return -EFAULT;
- +
- + to = &end_time;
- + if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
- + return -EINVAL;
- + }
- +
- + if (sigmask) {
- + if (sigsetsize != sizeof(sigset_t))
- + return -EINVAL;
- + if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
- + return -EFAULT;
- +
- + sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
- + sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
- + }
- +
- + ret = core_sys_select(n, inp, outp, exp, to);
- + ret = poll_select_copy_remaining_time32(&end_time, tsp, 0, ret);
- +
- + if (ret == -ERESTARTNOHAND) {
- + /*
- + * Don't restore the signal mask yet. Let do_signal() deliver
- + * the signal on the way back to userspace, before the signal
- + * mask is restored.
- + */
- + if (sigmask) {
- + memcpy(¤t->saved_sigmask, &sigsaved,
- + sizeof(sigsaved));
- + set_restore_sigmask();
- + }
- + } else if (sigmask)
- + sigprocmask(SIG_SETMASK, &sigsaved, NULL);
- +
- + return ret;
- +}
- +
- +SYSCALL_DEFINE6(pselect6_time32, int, n, fd_set __user *, inp,
- + fd_set __user *, outp, fd_set __user *, exp,
- + struct __kernel_old_timespec __user *, tsp, void __user *, sig)
- +{
- + size_t sigsetsize = 0;
- + sigset_t __user *up = NULL;
- +
- + if (sig) {
- + if (!access_ok(VERIFY_READ, sig, sizeof(void *)+sizeof(size_t))
- + || __get_user(up, (sigset_t __user * __user *)sig)
- + || __get_user(sigsetsize,
- + (size_t __user *)(sig+sizeof(void *))))
- + return -EFAULT;
- + }
- + return do_pselect_time32(n, inp, outp, exp, tsp, up, sigsetsize);
- +}
- +
- +SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds,
- + unsigned int, nfds, struct __kernel_old_timespec __user *, tsp,
- + const sigset_t __user *, sigmask, size_t, sigsetsize)
- +{
- + sigset_t ksigmask, sigsaved;
- + struct timespec64 ts, end_time, *to = NULL;
- + int ret;
- +
- + if (tsp) {
- + if (get_old_timespec(&ts, tsp))
- + return -EFAULT;
- +
- + to = &end_time;
- + if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
- + return -EINVAL;
- + }
- +
- + if (sigmask) {
- + if (sigsetsize != sizeof(sigset_t))
- + return -EINVAL;
- + if (copy_from_user(&ksigmask, sigmask, sizeof (ksigmask)))
- + return -EFAULT;
- +
- + sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
- + sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
- + }
- +
- + ret = do_sys_poll(ufds, nfds, to);
- +
- + /* We can restart this syscall, usually */
- + if (ret == -EINTR) {
- + /*
- + * Don't restore the signal mask yet. Let do_signal() deliver
- + * the signal on the way back to userspace, before the signal
- + * mask is restored.
- + */
- + if (sigmask) {
- + memcpy(¤t->saved_sigmask, &sigsaved,
- + sizeof(sigsaved));
- + set_restore_sigmask();
- + }
- + ret = -ERESTARTNOHAND;
- + } else if (sigmask)
- + sigprocmask(SIG_SETMASK, &sigsaved, NULL);
- +
- + ret = poll_select_copy_remaining_time32(&end_time, tsp, 0, ret);
- +
- + return ret;
- +}
- +#endif /* CONFIG_COMPAT_32BIT_TIME && !CONFIG_64BIT */
- +
- +#ifdef CONFIG_COMPAT
- #define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t))
- static
- @@ -1145,7 +1309,6 @@ int compat_poll_select_copy_remaining(struct timespec64 *end_time, void __user *
- return ret;
- }
- -#ifdef CONFIG_COMPAT
- /*
- * Ooo, nasty. We need here to frob 32-bit unsigned longs to
- * 64-bit unsigned longs.
- @@ -1170,18 +1333,6 @@ int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
- return 0;
- return compat_put_bitmap(ufdset, fdset, nr);
- }
- -#else
- -#define compat_get_fd_set get_fd_set
- -#define compat_set_fd_set set_fd_set
- -#define compat_sigset_t sigset_t
- -static inline int get_compat_sigset(sigset_t *set, const sigset_t __user *compat)
- -{
- - if (copy_from_user(set, compat, sizeof *set))
- - return -EFAULT;
- -
- - return 0;
- -}
- -#endif
- /*
- * This is a virtual copy of sys_select from fs/select.c and probably
- @@ -1266,7 +1417,6 @@ static int compat_core_sys_select(int n, compat_ulong_t __user *inp,
- out_nofds:
- return ret;
- }
- -#endif
- #ifdef CONFIG_COMPAT_32BIT_TIME
- static int do_compat_select(int n, compat_ulong_t __user *inp,
- @@ -1437,7 +1587,6 @@ COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds,
- }
- #endif
- -#ifdef CONFIG_COMPAT
- static long do_compat_pselect_time64(int n, compat_ulong_t __user *inp,
- compat_ulong_t __user *outp, compat_ulong_t __user *exp,
- struct __kernel_timespec __user *tsp, compat_sigset_t __user *sigmask,
- diff --git a/kernel/signal.c b/kernel/signal.c
- index 332f019dc421..d3e855a0dc45 100644
- --- a/kernel/signal.c
- +++ b/kernel/signal.c
- @@ -3140,6 +3140,40 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese,
- return ret;
- }
- +#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT)
- +SYSCALL_DEFINE4(rt_sigtimedwait_time32, sigset_t __user *, uthese,
- + struct siginfo __user *, uinfo,
- + struct __kernel_old_timespec __user *, uts,
- + size_t, sigsetsize)
- +{
- + sigset_t s;
- + struct timespec64 t;
- + siginfo_t info;
- + long ret;
- +
- + if (sigsetsize != sizeof(sigset_t))
- + return -EINVAL;
- +
- + if (copy_from_user(&s, uthese, sizeof(s)))
- + return -EFAULT;
- +
- + if (uts) {
- + if (get_old_timespec(&t, uts))
- + return -EFAULT;
- + }
- +
- + ret = do_sigtimedwait(&s, &info, uts ? &t : NULL);
- +
- + if (ret > 0 && uinfo) {
- + if (copy_siginfo_to_user(uinfo, &info))
- + ret = -EFAULT;
- + }
- +
- + return ret;
- +}
- +#endif
- +
- +#ifdef CONFIG_COMPAT
- #ifdef CONFIG_COMPAT_32BIT_TIME
- COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
- struct compat_siginfo __user *, uinfo,
- @@ -3172,7 +3206,6 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
- }
- #endif
- -#ifdef CONFIG_COMPAT
- COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait_time64, compat_sigset_t __user *, uthese,
- struct compat_siginfo __user *, uinfo,
- struct __kernel_timespec __user *, uts, compat_size_t, sigsetsize)
- diff --git a/net/compat.c b/net/compat.c
- index 5af2af1b9723..54d5f4e749e0 100644
- --- a/net/compat.c
- +++ b/net/compat.c
- @@ -841,6 +841,37 @@ COMPAT_SYSCALL_DEFINE5(recvmmsg_time64, int, fd, struct compat_mmsghdr __user *,
- return __compat_sys_recvmmsg_time64(fd, mmsg, vlen, flags, timeout);
- }
- +#ifdef CONFIG_COMPAT_32BIT_TIME
- +int __compat_sys_recvmmsg(int fd, struct mmsghdr __user *mmsg,
- + unsigned int vlen, unsigned int flags,
- + struct compat_timespec __user *timeout)
- +{
- + int datagrams;
- + struct timespec64 ktspec;
- +
- + if (timeout == NULL)
- + return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
- + flags | MSG_CMSG_COMPAT, NULL);
- +
- + if (compat_get_timespec64(&ktspec, timeout))
- + return -EFAULT;
- +
- + datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
- + flags | MSG_CMSG_COMPAT, &ktspec);
- + if (datagrams > 0 && compat_put_timespec64(&ktspec, timeout))
- + datagrams = -EFAULT;
- +
- + return datagrams;
- +}
- +
- +COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
- + unsigned int, vlen, unsigned int, flags,
- + struct compat_timespec __user *, timeout)
- +{
- + return __compat_sys_recvmmsg(fd, mmsg, vlen, flags, timeout);
- +}
- +#endif
- +
- COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
- {
- u32 a[AUDITSC_ARGS];
- diff --git a/net/socket.c b/net/socket.c
- index f4b6be81c6af..5d3e24e84974 100644
- --- a/net/socket.c
- +++ b/net/socket.c
- @@ -2474,33 +2474,36 @@ SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
- }
- #ifdef CONFIG_COMPAT_32BIT_TIME
- -int __compat_sys_recvmmsg(int fd, struct mmsghdr __user *mmsg,
- +int __sys_recvmmsg_time32(int fd, struct mmsghdr __user *mmsg,
- unsigned int vlen, unsigned int flags,
- - struct compat_timespec __user *timeout)
- + struct __kernel_old_timespec __user *timeout)
- {
- int datagrams;
- struct timespec64 ktspec;
- + if (flags & MSG_CMSG_COMPAT)
- + return -EINVAL;
- +
- if (timeout == NULL)
- return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
- - flags | MSG_CMSG_COMPAT, NULL);
- + flags, NULL);
- - if (compat_get_timespec64(&ktspec, timeout))
- + if (get_old_timespec(&ktspec, timeout))
- return -EFAULT;
- datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
- - flags | MSG_CMSG_COMPAT, &ktspec);
- - if (datagrams > 0 && compat_put_timespec64(&ktspec, timeout))
- + flags , &ktspec);
- + if (datagrams > 0 && put_old_timespec(&ktspec, timeout))
- datagrams = -EFAULT;
- return datagrams;
- }
- -COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
- +SYSCALL_DEFINE5(recvmmsg_time32, int, fd, struct mmsghdr __user *, mmsg,
- unsigned int, vlen, unsigned int, flags,
- - struct compat_timespec __user *, timeout)
- + struct __kernel_old_timespec __user *, timeout)
- {
- - return __compat_sys_recvmmsg(fd, mmsg, vlen, flags, timeout);
- + return __sys_recvmmsg_time32(fd, mmsg, vlen, flags, timeout);
- }
- #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement