Signed-off-by: Arnd Bergmann <[email protected]>
---
 include/linux/compat_time.h |  3 +++
 include/net/compat.h        |  3 +++
 include/uapi/linux/net.h    |  1 +
 net/compat.c                | 18 ++++++++++++------
 net/socket.c                | 36 ++++++++++++++++++++++++++++++++++--
 5 files changed, 53 insertions(+), 8 deletions(-)

diff --git a/include/linux/compat_time.h b/include/linux/compat_time.h
index dada7bd49f58..6d129a7f3843 100644
--- a/include/linux/compat_time.h
+++ b/include/linux/compat_time.h
@@ -244,6 +244,9 @@ struct compat_mmsghdr;
 asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
                                    unsigned vlen, unsigned int flags,
                                    struct compat_timespec __user *timeout);
+asmlinkage long compat_sys_recvmmsg64(int fd, struct compat_mmsghdr __user 
*mmsg,
+                                   unsigned vlen, unsigned int flags,
+                                   struct __kernel_timespec __user *timeout);
 asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
                                     struct compat_timespec __user *rmtp);
 asmlinkage long compat_sys_getitimer(int which,
diff --git a/include/net/compat.h b/include/net/compat.h
index 48103cf94e97..dbb5b6b949c5 100644
--- a/include/net/compat.h
+++ b/include/net/compat.h
@@ -51,6 +51,9 @@ asmlinkage long compat_sys_recvmsg(int, struct compat_msghdr 
__user *,
 asmlinkage long compat_sys_recvmmsg(int, struct compat_mmsghdr __user *,
                                    unsigned int, unsigned int,
                                    struct compat_timespec __user *);
+asmlinkage long compat_sys_recvmmsg64(int, struct compat_mmsghdr __user *,
+                                   unsigned int, unsigned int,
+                                   struct __kernel_timespec __user *);
 asmlinkage long compat_sys_getsockopt(int, int, int, char __user *,
                                      int __user *);
 int put_cmsg_compat(struct msghdr*, int, int, int, void *);
diff --git a/include/uapi/linux/net.h b/include/uapi/linux/net.h
index 9457239ed219..7601df60f380 100644
--- a/include/uapi/linux/net.h
+++ b/include/uapi/linux/net.h
@@ -43,6 +43,7 @@
 #define SYS_ACCEPT4    18              /* sys_accept4(2)               */
 #define SYS_RECVMMSG   19              /* sys_recvmmsg(2)              */
 #define SYS_SENDMMSG   20              /* sys_sendmmsg(2)              */
+#define SYS_RECVMMSG64 21              /* sys_recvmmsg(2), time64_t    */
 
 typedef enum {
        SS_FREE = 0,                    /* not allocated                */
diff --git a/net/compat.c b/net/compat.c
index 5cfd26a0006f..15c326adbb6c 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -743,23 +743,23 @@ COMPAT_SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, 
buf, compat_size_t, len
        return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, 
addrlen);
 }
 
-COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
+COMPAT_SYSCALL_DEFINE5(recvmmsg64, int, fd, struct compat_mmsghdr __user *, 
mmsg,
                       unsigned int, vlen, unsigned int, flags,
-                      struct compat_timespec __user *, timeout)
+                      struct __kernel_timespec __user *, timeout)
 {
        int datagrams;
-       struct timespec ktspec;
+       struct timespec64 timeout_sys;
 
        if (timeout == NULL)
                return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
                                      flags | MSG_CMSG_COMPAT, NULL);
 
-       if (compat_get_timespec(&ktspec, timeout))
+       if (get_timespec64(&timeout_sys, timeout))
                return -EFAULT;
 
        datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
-                                  flags | MSG_CMSG_COMPAT, &ktspec);
-       if (datagrams > 0 && compat_put_timespec(&ktspec, timeout))
+                                  flags | MSG_CMSG_COMPAT, &timeout_sys);
+       if (datagrams > 0 && put_timespec64(&timeout_sys, timeout))
                datagrams = -EFAULT;
 
        return datagrams;
@@ -836,13 +836,19 @@ COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user 
*, args)
        case SYS_RECVMSG:
                ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
                break;
+#ifdef CONFIG_COMPAT_TIME
        case SYS_RECVMMSG:
                ret = compat_sys_recvmmsg(a0, compat_ptr(a1), a[2], a[3],
                                          compat_ptr(a[4]));
                break;
+#endif
        case SYS_ACCEPT4:
                ret = sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]);
                break;
+       case SYS_RECVMMSG64:
+               ret = compat_sys_recvmmsg64(a0, compat_ptr(a1), a[2], a[3],
+                                         compat_ptr(a[4]));
+               break;
        default:
                ret = -EINVAL;
                break;
diff --git a/net/socket.c b/net/socket.c
index bfe50f60688b..632e0004c972 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2197,6 +2197,9 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, 
unsigned int vlen,
        entry = mmsg;
        compat_entry = (struct compat_mmsghdr __user *)mmsg;
 
+       if (!IS_ENABLED(CONFIG_COMPAT))
+               flags &= ~MSG_CMSG_COMPAT;
+
        while (datagrams < vlen) {
                /*
                 * No need to ask LSM for more than the first datagram.
@@ -2291,13 +2294,36 @@ SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr 
__user *, mmsg,
 
        datagrams = __sys_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys);
 
-       if (datagrams > 0 &&
-           put_timespec64(&timeout_sys, timeout))
+       if (datagrams > 0 && put_timespec64(&timeout_sys, timeout))
                datagrams = -EFAULT;
 
        return datagrams;
 }
 
+#ifdef CONFIG_COMPAT_TIME
+COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_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;
+}
+#endif
+
 #ifdef __ARCH_WANT_SYS_SOCKETCALL
 /* Argument list sizes for sys_socketcall */
 #define AL(x) ((x) * sizeof(unsigned long))
@@ -2409,6 +2435,12 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long 
__user *, args)
                err = sys_recvmsg(a0, (struct user_msghdr __user *)a1, a[2]);
                break;
        case SYS_RECVMMSG:
+#if !defined(CONFIG_64BIT) && defined(CONFIG_COMPAT_TIME)
+               err = compat_sys_recvmmsg(a0, (struct mmsghdr __user *)a1, 
a[2], a[3],
+                                         (struct compat_timespec __user 
*)a[4]);
+               break;
+       case SYS_RECVMMSG64:
+#endif
                err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
                                   (struct __kernel_timespec __user *)a[4]);
                break;
-- 
2.1.0.rc2

_______________________________________________
Y2038 mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/y2038

Reply via email to