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