From patchwork Tue Sep 8 14:57:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 40380 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DFE1839518B4; Tue, 8 Sep 2020 14:58:05 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DFE1839518B4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1599577085; bh=hd4R9Ey7VEkEAY4U6BpjGA6Hz+uYun5WyCNFQZQQInY=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=cwrlqM+qWlL+ZzZWg5TfpgkAYOi0SGSfg7TR6tprgclH/TvvlobPQd6DvM526Sqei OBiy5RrQHaCG3Whqxu8c6ZmSQcM7MkAfxdXWRDtdVvxkIjloopqupOrwJ22QlyEU8M fvidOzJew87eI/KPEfcQJ7tbxqQt8I/sTRg7NtsU= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qt1-x843.google.com (mail-qt1-x843.google.com [IPv6:2607:f8b0:4864:20::843]) by sourceware.org (Postfix) with ESMTPS id 9D42B39518B8 for ; Tue, 8 Sep 2020 14:58:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 9D42B39518B8 Received: by mail-qt1-x843.google.com with SMTP id n18so12139500qtw.0 for ; Tue, 08 Sep 2020 07:58:02 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=hd4R9Ey7VEkEAY4U6BpjGA6Hz+uYun5WyCNFQZQQInY=; b=iJHFKrr1F/acRGSf9KFIbIbpHOYxBKDWNN6E5cu5p7S/gtbHcMksgPqB/OFxpvgFnO RgxbAW5qZzgc037+S166L70lk7zWsD4MqSFSSWNdZ8GoEYYoVwK8V3RjRqpB1uEALl1n LZbFaWEjVTpWoC6zveVofgk3Lr7R8krfZBAB7mTTuasxEBL9v99hE0n8Rzh5jfkv+dzn kpj28IEAJJDBQJyzxmf5JaZQbmWbu3NajCR7UVObrceHX8uC7j3p16f+W4KWxFvVamSx fcP+wRUrAKVwTLZjQm2COAaVJIp6e9KZ7f4ltoU6SQ45JRvf0UWd9IpVm3wR/JBU9ryq iStA== X-Gm-Message-State: AOAM533WUfDOHHEYI4s/ks9vlZzhorgXwHUhI6JZsOJJOj0Ja/x859jc 7nApKYAwPevpn5omsC9KjGBqhwHqjpBtOg== X-Google-Smtp-Source: ABdhPJwTGBlo+iVOZDmhI2jq2+nXo7JzUhoIl0tgnXxtdLRna8FQq715MZtBoAHluDWXKpC6hQ8M2A== X-Received: by 2002:ac8:f04:: with SMTP id e4mr441645qtk.342.1599577081002; Tue, 08 Sep 2020 07:58:01 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id e188sm10800748qkd.55.2020.09.08.07.58.00 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2020 07:58:00 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [RFC 12/14] linux: Add fallback for 64-bit time_t SO_{RCV,SND}TIMEO Date: Tue, 8 Sep 2020 11:57:36 -0300 Message-Id: <20200908145738.640039-12-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200908145738.640039-1-adhemerval.zanella@linaro.org> References: <20200908145738.640039-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Netto Reply-To: Adhemerval Zanella Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" 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). --- .../unix/sysv/linux/bits/socket-constants.h | 19 ++--- sysdeps/unix/sysv/linux/getsockopt.c | 72 ++++++++++++++++-- .../sysv/linux/hppa/bits/socket-constants.h | 15 +++- .../sysv/linux/mips/bits/socket-constants.h | 17 ++++- .../linux/powerpc/bits/socket-constants.h | 19 ++++- sysdeps/unix/sysv/linux/setsockopt.c | 76 +++++++++++++++++-- .../sysv/linux/sparc/bits/socket-constants.h | 17 ++++- 7 files changed, 202 insertions(+), 33 deletions(-) diff --git a/sysdeps/unix/sysv/linux/bits/socket-constants.h b/sysdeps/unix/sysv/linux/bits/socket-constants.h index d02e1cbc7c..c7478651fb 100644 --- a/sysdeps/unix/sysv/linux/bits/socket-constants.h +++ b/sysdeps/unix/sysv/linux/bits/socket-constants.h @@ -32,19 +32,20 @@ #define SO_OOBINLINE 10 #define SO_RCVBUF 8 #define SO_RCVLOWAT 18 -#if (__TIMESIZE == 64 && __WORDSIZE == 32 \ - && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) -# define SO_RCVTIMEO 66 -#else -# define SO_RCVTIMEO 20 -#endif #define SO_REUSEADDR 2 #define SO_SNDBUF 7 #define SO_SNDLOWAT 19 +#define SO_TYPE 3 + +#define SO_RCVTIMEO_OLD 20 +#define SO_SNDTIMEO_OLD 21 +#define SO_RCVTIMEO_NEW 66 +#define SO_SNDTIMEO_NEW 67 #if (__TIMESIZE == 64 && __WORDSIZE == 32 \ && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) -# define SO_SNDTIMEO 67 +# define SO_RCVTIMEO SO_RCVTIMEO_NEW +# define SO_SNDTIMEO SO_SNDTIMEO_NEW #else -# define SO_SNDTIMEO 21 +# define SO_RCVTIMEO SO_RCVTIMEO_OLD +# define SO_SNDTIMEO SO_SNDTIMEO_OLD #endif -#define SO_TYPE 3 diff --git a/sysdeps/unix/sysv/linux/getsockopt.c b/sysdeps/unix/sysv/linux/getsockopt.c index 11939660c1..5dce0e29ee 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 fda7f95d44..eca5fe045c 100644 --- a/sysdeps/unix/sysv/linux/hppa/bits/socket-constants.h +++ b/sysdeps/unix/sysv/linux/hppa/bits/socket-constants.h @@ -30,9 +30,20 @@ #define SO_OOBINLINE 256 #define SO_RCVBUF 4098 #define SO_RCVLOWAT 4100 -#define SO_RCVTIMEO 4102 #define SO_REUSEADDR 4 #define SO_SNDBUF 4097 #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 +#if (__TIMESIZE == 64 && __WORDSIZE == 32 \ + && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) +# define SO_RCVTIMEO SO_RCVTIMEO_NEW +# define SO_SNDTIMEO SO_SNDTIMEO_NEW +#else +# define SO_RCVTIMEO SO_RCVTIMEO_OLD +# define SO_SNDTIMEO SO_SNDTIMEO_OLD +#endif diff --git a/sysdeps/unix/sysv/linux/mips/bits/socket-constants.h b/sysdeps/unix/sysv/linux/mips/bits/socket-constants.h index daa47c6c7c..961fad21b8 100644 --- a/sysdeps/unix/sysv/linux/mips/bits/socket-constants.h +++ b/sysdeps/unix/sysv/linux/mips/bits/socket-constants.h @@ -20,6 +20,8 @@ # error "Never include directly; use instead." #endif +#include + #define SOL_SOCKET 65535 #define SO_ACCEPTCONN 4105 #define SO_BROADCAST 32 @@ -30,9 +32,20 @@ #define SO_OOBINLINE 256 #define SO_RCVBUF 4098 #define SO_RCVLOWAT 4100 -#define SO_RCVTIMEO 4102 #define SO_REUSEADDR 4 #define SO_SNDBUF 4097 #define SO_SNDLOWAT 4099 -#define SO_SNDTIMEO 4101 #define SO_TYPE 4104 + +#define SO_RCVTIMEO_OLD 4100 +#define SO_SNDTIMEO_OLD 4101 +#define SO_RCVTIMEO_NEW 66 +#define SO_SNDTIMEO_NEW 67 +#if (__TIMESIZE == 64 && __WORDSIZE == 32 \ + && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) +# define SO_RCVTIMEO SO_RCVTIMEO_NEW +# define SO_SNDTIMEO SO_SNDTIMEO_NEW +#else +# define SO_RCVTIMEO SO_RCVTIMEO_OLD +# define SO_SNDTIMEO SO_SNDTIMEO_OLD +#endif diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/socket-constants.h b/sysdeps/unix/sysv/linux/powerpc/bits/socket-constants.h index 77fc8b207e..d0ec3cb4fc 100644 --- a/sysdeps/unix/sysv/linux/powerpc/bits/socket-constants.h +++ b/sysdeps/unix/sysv/linux/powerpc/bits/socket-constants.h @@ -20,6 +20,8 @@ # error "Never include directly; use instead." #endif +#include + #define SOL_SOCKET 1 #define SO_ACCEPTCONN 30 #define SO_BROADCAST 6 @@ -30,9 +32,20 @@ #define SO_OOBINLINE 10 #define SO_RCVBUF 8 #define SO_RCVLOWAT 16 -#define SO_RCVTIMEO 18 #define SO_REUSEADDR 2 #define SO_SNDBUF 7 -#define SO_SNDLOWAT 17 -#define SO_SNDTIMEO 19 +#define SO_SNDTIMEO 67 #define SO_TYPE 3 + +#define SO_RCVTIMEO_OLD 18 +#define SO_SNDTIMEO_OLD 19 +#define SO_RCVTIMEO_NEW 66 +#define SO_SNDTIMEO_NEW 67 +#if (__TIMESIZE == 64 && __WORDSIZE == 32 \ + && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) +# define SO_RCVTIMEO SO_RCVTIMEO_NEW +# define SO_SNDTIMEO SO_SNDTIMEO_NEW +#else +# define SO_RCVTIMEO SO_RCVTIMEO_OLD +# define SO_SNDTIMEO SO_SNDTIMEO_OLD +#endif diff --git a/sysdeps/unix/sysv/linux/setsockopt.c b/sysdeps/unix/sysv/linux/setsockopt.c index 20c0868783..ebc32d788c 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 6ef575e521..d4bf8f79d6 100644 --- a/sysdeps/unix/sysv/linux/sparc/bits/socket-constants.h +++ b/sysdeps/unix/sysv/linux/sparc/bits/socket-constants.h @@ -20,6 +20,8 @@ # error "Never include directly; use instead." #endif +#include + #define SOL_SOCKET 65535 #define SO_ACCEPTCONN 32768 #define SO_BROADCAST 32 @@ -30,9 +32,20 @@ #define SO_OOBINLINE 256 #define SO_RCVBUF 4098 #define SO_RCVLOWAT 2048 -#define SO_RCVTIMEO 8192 #define SO_REUSEADDR 4 #define SO_SNDBUF 4097 #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 +#if (__TIMESIZE == 64 && __WORDSIZE == 32 \ + && (!defined __SYSCALL_WORDSIZE || __SYSCALL_WORDSIZE == 32)) +# define SO_RCVTIMEO SO_RCVTIMEO_NEW +# define SO_SNDTIMEO SO_SNDTIMEO_NEW +#else +# define SO_RCVTIMEO SO_RCVTIMEO_OLD +# define SO_SNDTIMEO SO_SNDTIMEO_OLD +#endif