diff options
author | Arnd Bergmann <arnd@arndb.de> | 2018-04-18 07:43:52 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2018-12-18 10:13:04 -0500 |
commit | e11d4284e2f4de5048c6d1787c82226f0a198292 (patch) | |
tree | bc52de794fd0fc90e2842a9d680239d6c3e9c215 /net/compat.c | |
parent | bec2f7cbb73eadf5e1cc7d54ecb0980ede244257 (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.c | 34 |
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 | ||
813 | static int __compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg, | 813 | COMPAT_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 | ||
835 | COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg, | 822 | COMPAT_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 | ||
842 | COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args) | 831 | COMPAT_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]); |