Following directly what we did for sys_pselect6 compat_time handling, this adds the same method for sys_ppoll.
Signed-off-by: Arnd Bergmann arnd@arndb.de --- fs/compat.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-)
diff --git a/fs/compat.c b/fs/compat.c index e4fffe221d37..3e7ccc6e3503 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -1409,19 +1409,26 @@ COMPAT_SYSCALL_DEFINE6(pselect6, int, n, compat_ulong_t __user *, inp, return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up), sigsetsize, 1); } +#endif
-COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, - unsigned int, nfds, struct compat_timespec __user *, tsp, - const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) +static int do_compat_ppoll(struct pollfd __user *ufds, + unsigned int nfds, void __user *tsp, + const compat_sigset_t __user * sigmask, compat_size_t sigsetsize, + int compat_time) { sigset_t ksigmask, sigsaved; - struct compat_timespec ts; + struct timespec64 ts; struct timespec64 end_time, *to = NULL; int ret;
if (tsp) { - if (copy_from_user(&ts, tsp, sizeof(ts))) - return -EFAULT; + if (compat_time) { + if (compat_get_timespec64(&ts, tsp)) + return -EFAULT; + } else { + if (get_timespec64(&ts, tsp)) + return -EFAULT; + }
to = &end_time; if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) @@ -1454,10 +1461,18 @@ COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, } else if (sigmask) sigprocmask(SIG_SETMASK, &sigsaved, NULL);
- ret = poll_select_copy_remaining(&end_time, tsp, 0, 1, ret); + ret = poll_select_copy_remaining(&end_time, tsp, 0, compat_time, ret);
return ret; } + +#ifdef CONFIG_COMPAT_TIME +COMPAT_SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, + unsigned int, nfds, struct compat_timespec __user *, tsp, + const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) +{ + return do_compat_ppoll(ufds, nfds, tsp, sigmask, sigsetsize, 1); +} #endif
#ifdef CONFIG_COMPAT @@ -1479,6 +1494,14 @@ COMPAT_SYSCALL_DEFINE6(pselect6_time64, int, n, compat_ulong_t __user *, inp, return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up), sigsetsize, 0); } + +COMPAT_SYSCALL_DEFINE5(ppoll_time64, struct pollfd __user *, ufds, + unsigned int, nfds, struct compat_timespec __user *, tsp, + const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) +{ + return do_compat_ppoll(ufds, nfds, tsp, sigmask, sigsetsize, 0); +} + #endif
#if defined(CONFIG_FHANDLE) && defined(CONFIG_COMPAT)