From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1791) id 485CC388C01D; Tue, 2 Mar 2021 12:30:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 485CC388C01D Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Adhemerval Zanella To: glibc-cvs@sourceware.org Subject: [glibc/azanella/y2038] linux: Add fallback for 64-bit time_t SO_{RCV, SND}TIMEO X-Act-Checkin: glibc X-Git-Author: Adhemerval Zanella X-Git-Refname: refs/heads/azanella/y2038 X-Git-Oldrev: 8a0990ba29bf93ff775fd7c2acf866716bfb2435 X-Git-Newrev: 7a9d006fb51b7889580a07a7fc874a3354c3b9df Message-Id: <20210302123024.485CC388C01D@sourceware.org> Date: Tue, 2 Mar 2021 12:30:24 +0000 (GMT) X-BeenThere: glibc-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Glibc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Mar 2021 12:30:24 -0000 https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=7a9d006fb51b7889580a07a7fc874a3354c3b9df commit 7a9d006fb51b7889580a07a7fc874a3354c3b9df Author: Adhemerval Zanella Date: Mon Sep 7 14:13:58 2020 -0300 linux: Add fallback for 64-bit time_t SO_{RCV,SND}TIMEO The constant value will be changed for __TIMESIZE=64, so binaries built with 64-bit time support might fail to work properly on old kernels. Both {get,set}sockopt will retry the syscall with the old constant values and the timeout value adjusted when kernel returns ENOTPROTOPT. It also changes to SO_{RCV,SND}TIMEO to follow the uapi kernel values where SO_{RCV,SND}TIMEO_OLD indicates pre 64-bit time support and SO_{RCV,SND}TIMEO_NEW indicate time64 support. It allows to refer to constant independently of the time_t abi used (since kernel defines SO_{RCV,SND}TIMEO depending of the time_t size). The hppa, mips, powerpc, and sparc provides its own socket-constant.h, which are also updated the the SO_{RCV,SND}TIMEO constants (they are missed on 019d828669df966 patch). Checked on x86_64-linux-gnu and i686-linux-gnu (on 5.4 and on 4.15 kernel). Diff: --- sysdeps/unix/sysv/linux/bits/socket-constants.h | 5 ++ sysdeps/unix/sysv/linux/getsockopt.c | 72 ++++++++++++++++++-- .../unix/sysv/linux/hppa/bits/socket-constants.h | 5 ++ .../unix/sysv/linux/mips/bits/socket-constants.h | 5 ++ .../sysv/linux/powerpc/bits/socket-constants.h | 5 ++ sysdeps/unix/sysv/linux/setsockopt.c | 76 +++++++++++++++++++--- .../unix/sysv/linux/sparc/bits/socket-constants.h | 5 ++ 7 files changed, 158 insertions(+), 15 deletions(-) diff --git a/sysdeps/unix/sysv/linux/bits/socket-constants.h b/sysdeps/unix/sysv/linux/bits/socket-constants.h index 84f7a333a2..d4e9979605 100644 --- a/sysdeps/unix/sysv/linux/bits/socket-constants.h +++ b/sysdeps/unix/sysv/linux/bits/socket-constants.h @@ -48,3 +48,8 @@ # define SO_SNDTIMEO 21 #endif #define SO_TYPE 3 + +#define SO_RCVTIMEO_OLD 20 +#define SO_SNDTIMEO_OLD 21 +#define SO_RCVTIMEO_NEW 66 +#define SO_SNDTIMEO_NEW 67 diff --git a/sysdeps/unix/sysv/linux/getsockopt.c b/sysdeps/unix/sysv/linux/getsockopt.c index 76ee8a94d6..a093e42f96 100644 --- a/sysdeps/unix/sysv/linux/getsockopt.c +++ b/sysdeps/unix/sysv/linux/getsockopt.c @@ -15,16 +15,20 @@ License along with the GNU C Library; if not, see . */ -#include -#include #include - +/* The kernel header with SO_* constants is used as default for _GNU_SOURCE, + however the new constants that describe 64-bit time support were added + only on v5.1. */ +#if !defined(SO_RCVTIMEO_NEW) || !defined(SO_RCVTIMEO_OLD) +# include +#endif +#include +#include #include -#include -#include -int -__getsockopt (int fd, int level, int optname, void *optval, socklen_t *len) +static int +getsockopt_syscall (int fd, int level, int optname, void *optval, + socklen_t *len) { #ifdef __ASSUME_GETSOCKOPT_SYSCALL return INLINE_SYSCALL (getsockopt, 5, fd, level, optname, optval, len); @@ -32,4 +36,58 @@ __getsockopt (int fd, int level, int optname, void *optval, socklen_t *len) return SOCKETCALL (getsockopt, fd, level, optname, optval, len); #endif } + +#ifndef __ASSUME_TIME64_SYSCALLS +static int +getsockopt32 (int fd, int level, int optname, void *optval, + socklen_t *len) +{ + int r = -1; + + if (level != SOL_SOCKET) + return r; + + switch (optname) + { + case SO_RCVTIMEO_NEW: + case SO_SNDTIMEO_NEW: + { + if (*len < sizeof (struct __timeval64)) + { + __set_errno (EINVAL); + break; + } + + if (optname == SO_RCVTIMEO_NEW) + optname = SO_RCVTIMEO_OLD; + if (optname == SO_SNDTIMEO_NEW) + optname = SO_SNDTIMEO_OLD; + + struct __timeval32 tv32; + r = getsockopt_syscall (fd, level, optname, &tv32, + (socklen_t[]) { sizeof tv32 }); + if (r < 0) + break; + struct __timeval64 *tv64 = (struct __timeval64 *) optval; + *tv64 = valid_timeval32_to_timeval64 (tv32); + *len = sizeof (*tv64); + } + } + + return r; +} +#endif + +int +__getsockopt (int fd, int level, int optname, void *optval, socklen_t *len) +{ + int r = getsockopt_syscall (fd, level, optname, optval, len); + +#ifndef __ASSUME_TIME64_SYSCALLS + if (r == -1 && errno == ENOPROTOOPT) + r = getsockopt32 (fd, level, optname, optval, len); +#endif + + return r; +} weak_alias (__getsockopt, getsockopt) diff --git a/sysdeps/unix/sysv/linux/hppa/bits/socket-constants.h b/sysdeps/unix/sysv/linux/hppa/bits/socket-constants.h index b4fb65b9f1..2413529e71 100644 --- a/sysdeps/unix/sysv/linux/hppa/bits/socket-constants.h +++ b/sysdeps/unix/sysv/linux/hppa/bits/socket-constants.h @@ -36,3 +36,8 @@ #define SO_SNDLOWAT 4099 #define SO_SNDTIMEO 4101 #define SO_TYPE 4104 + +#define SO_RCVTIMEO_OLD 4102 +#define SO_SNDTIMEO_OLD 4101 +#define SO_RCVTIMEO_NEW 16448 +#define SO_SNDTIMEO_NEW 16449 diff --git a/sysdeps/unix/sysv/linux/mips/bits/socket-constants.h b/sysdeps/unix/sysv/linux/mips/bits/socket-constants.h index a5264536e9..2c124234fc 100644 --- a/sysdeps/unix/sysv/linux/mips/bits/socket-constants.h +++ b/sysdeps/unix/sysv/linux/mips/bits/socket-constants.h @@ -36,3 +36,8 @@ #define SO_SNDLOWAT 4099 #define SO_SNDTIMEO 4101 #define SO_TYPE 4104 + +#define SO_RCVTIMEO_OLD 4102 +#define SO_SNDTIMEO_OLD 4101 +#define SO_RCVTIMEO_NEW 66 +#define SO_SNDTIMEO_NEW 67 diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/socket-constants.h b/sysdeps/unix/sysv/linux/powerpc/bits/socket-constants.h index f35488b375..682a3f4608 100644 --- a/sysdeps/unix/sysv/linux/powerpc/bits/socket-constants.h +++ b/sysdeps/unix/sysv/linux/powerpc/bits/socket-constants.h @@ -36,3 +36,8 @@ #define SO_SNDLOWAT 17 #define SO_SNDTIMEO 19 #define SO_TYPE 3 + +#define SO_RCVTIMEO_OLD 18 +#define SO_SNDTIMEO_OLD 19 +#define SO_RCVTIMEO_NEW 66 +#define SO_SNDTIMEO_NEW 67 diff --git a/sysdeps/unix/sysv/linux/setsockopt.c b/sysdeps/unix/sysv/linux/setsockopt.c index 12fd7bdcde..a1f98a937d 100644 --- a/sysdeps/unix/sysv/linux/setsockopt.c +++ b/sysdeps/unix/sysv/linux/setsockopt.c @@ -15,21 +15,81 @@ License along with the GNU C Library; if not, see . */ -#include -#include #include - +/* The kernel header with SO_* constants is used as default for _GNU_SOURCE, + however the new constants that describe 64-bit time support were added + only on v5.1. */ +#if !defined(SO_RCVTIMEO_NEW) || !defined(SO_RCVTIMEO_OLD) +# include +#endif +#include +#include #include -#include -#include -int -setsockopt (int fd, int level, int optname, const void *optval, socklen_t len) +static int +setsockopt_syscall (int fd, int level, int optname, const void *optval, + socklen_t len) { #ifdef __ASSUME_SETSOCKOPT_SYSCALL - return INLINE_SYSCALL (setsockopt, 5, fd, level, optname, optval, len); + return INLINE_SYSCALL_CALL (setsockopt, fd, level, optname, optval, len); #else return SOCKETCALL (setsockopt, fd, level, optname, optval, len); #endif } + +#ifndef __ASSUME_TIME64_SYSCALLS +static int +setsockopt32 (int fd, int level, int optname, const void *optval, + socklen_t len) +{ + int r = -1; + + if (level != SOL_SOCKET) + return r; + + switch (optname) + { + case SO_RCVTIMEO_NEW: + case SO_SNDTIMEO_NEW: + { + if (len < sizeof (struct __timeval64)) + { + __set_errno (EINVAL); + break; + } + + struct __timeval64 *tv64 = (struct __timeval64 *) optval; + if (! in_time_t_range (tv64->tv_sec)) + { + __set_errno (EOVERFLOW); + break; + } + + if (optname == SO_RCVTIMEO_NEW) + optname = SO_RCVTIMEO_OLD; + if (optname == SO_SNDTIMEO_NEW) + optname = SO_SNDTIMEO_OLD; + + struct __timeval32 tv32 = valid_timeval64_to_timeval32 (*tv64); + + r = setsockopt_syscall (fd, level, optname, &tv32, sizeof (tv32)); + } + } + + return r; +} +#endif + +int +setsockopt (int fd, int level, int optname, const void *optval, socklen_t len) +{ + int r = setsockopt_syscall (fd, level, optname, optval, len); + +#ifndef __ASSUME_TIME64_SYSCALLS + if (r == -1 && errno == ENOPROTOOPT) + r = setsockopt32 (fd, level, optname, optval, len); +#endif + + return r; +} weak_alias (setsockopt, __setsockopt) diff --git a/sysdeps/unix/sysv/linux/sparc/bits/socket-constants.h b/sysdeps/unix/sysv/linux/sparc/bits/socket-constants.h index a58d0b5f96..3eae2176dd 100644 --- a/sysdeps/unix/sysv/linux/sparc/bits/socket-constants.h +++ b/sysdeps/unix/sysv/linux/sparc/bits/socket-constants.h @@ -36,3 +36,8 @@ #define SO_SNDLOWAT 4096 #define SO_SNDTIMEO 16384 #define SO_TYPE 4104 + +#define SO_RCVTIMEO_OLD 8192 +#define SO_SNDTIMEO_OLD 16384 +#define SO_RCVTIMEO_NEW 68 +#define SO_SNDTIMEO_NEW 69