summaryrefslogtreecommitdiffstats
path: root/net/compat.c
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2018-04-18 07:43:52 -0400
committerArnd Bergmann <arnd@arndb.de>2018-12-18 10:13:04 -0500
commite11d4284e2f4de5048c6d1787c82226f0a198292 (patch)
treebc52de794fd0fc90e2842a9d680239d6c3e9c215 /net/compat.c
parentbec2f7cbb73eadf5e1cc7d54ecb0980ede244257 (diff)
y2038: socket: Add compat_sys_recvmmsg_time64
recvmmsg() takes two arguments to pointers of structures that differ between 32-bit and 64-bit architectures: mmsghdr and timespec. For y2038 compatbility, we are changing the native system call from timespec to __kernel_timespec with a 64-bit time_t (in another patch), and use the existing compat system call on both 32-bit and 64-bit architectures for compatibility with traditional 32-bit user space. As we now have two variants of recvmmsg() for 32-bit tasks that are both different from the variant that we use on 64-bit tasks, this means we also require two compat system calls! The solution I picked is to flip things around: The existing compat_sys_recvmmsg() call gets moved from net/compat.c into net/socket.c and now handles the case for old user space on all architectures that have set CONFIG_COMPAT_32BIT_TIME. A new compat_sys_recvmmsg_time64() call gets added in the old place for 64-bit architectures only, this one handles the case of a compat mmsghdr structure combined with __kernel_timespec. In the indirect sys_socketcall(), we now need to call either do_sys_recvmmsg() or __compat_sys_recvmmsg(), depending on what kind of architecture we are on. For compat_sys_socketcall(), no such change is needed, we always call __compat_sys_recvmmsg(). I decided to not add a new SYS_RECVMMSG_TIME64 socketcall: Any libc implementation for 64-bit time_t will need significant changes including an updated asm/unistd.h, and it seems better to consistently use the separate syscalls that configuration, leaving the socketcall only for backward compatibility with 32-bit time_t based libc. The naming is asymmetric for the moment, so both existing syscalls entry points keep their names, while the new ones are recvmmsg_time32 and compat_recvmmsg_time64 respectively. I expect that we will rename the compat syscalls later as we start using generated syscall tables everywhere and add these entry points. Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'net/compat.c')
-rw-r--r--net/compat.c34
1 files changed, 12 insertions, 22 deletions
diff --git a/net/compat.c b/net/compat.c
index 47a614b370cd..f7084780a8f8 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -810,34 +810,23 @@ COMPAT_SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, buf, compat_size_t, len
810 return __compat_sys_recvfrom(fd, buf, len, flags, addr, addrlen); 810 return __compat_sys_recvfrom(fd, buf, len, flags, addr, addrlen);
811} 811}
812 812
813static int __compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg, 813COMPAT_SYSCALL_DEFINE5(recvmmsg_time64, int, fd, struct compat_mmsghdr __user *, mmsg,
814 unsigned int vlen, unsigned int flags, 814 unsigned int, vlen, unsigned int, flags,
815 struct old_timespec32 __user *timeout) 815 struct __kernel_timespec __user *, timeout)
816{ 816{
817 int datagrams; 817 return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
818 struct timespec64 ktspec; 818 flags | MSG_CMSG_COMPAT, timeout, NULL);
819
820 if (timeout == NULL)
821 return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
822 flags | MSG_CMSG_COMPAT, NULL);
823
824 if (compat_get_timespec64(&ktspec, timeout))
825 return -EFAULT;
826
827 datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
828 flags | MSG_CMSG_COMPAT, &ktspec);
829 if (datagrams > 0 && compat_put_timespec64(&ktspec, timeout))
830 datagrams = -EFAULT;
831
832 return datagrams;
833} 819}
834 820
821#ifdef CONFIG_COMPAT_32BIT_TIME
835COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg, 822COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
836 unsigned int, vlen, unsigned int, flags, 823 unsigned int, vlen, unsigned int, flags,
837 struct old_timespec32 __user *, timeout) 824 struct old_timespec32 __user *, timeout)
838{ 825{
839 return __compat_sys_recvmmsg(fd, mmsg, vlen, flags, timeout); 826 return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
827 flags | MSG_CMSG_COMPAT, NULL, timeout);
840} 828}
829#endif
841 830
842COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args) 831COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
843{ 832{
@@ -925,8 +914,9 @@ COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
925 ret = __compat_sys_recvmsg(a0, compat_ptr(a1), a[2]); 914 ret = __compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
926 break; 915 break;
927 case SYS_RECVMMSG: 916 case SYS_RECVMMSG:
928 ret = __compat_sys_recvmmsg(a0, compat_ptr(a1), a[2], a[3], 917 ret = __sys_recvmmsg(a0, compat_ptr(a1), a[2],
929 compat_ptr(a[4])); 918 a[3] | MSG_CMSG_COMPAT, NULL,
919 compat_ptr(a[4]));
930 break; 920 break;
931 case SYS_ACCEPT4: 921 case SYS_ACCEPT4:
932 ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]); 922 ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]);