public inbox for glibc-cvs@sourceware.org
help / color / mirror / Atom feed
From: Adhemerval Zanella <azanella@sourceware.org>
To: glibc-cvs@sourceware.org
Subject: [glibc/azanella/y2038] linux: Add fallback for 64-bit time_t SO_{RCV,  SND}TIMEO
Date: Tue,  2 Mar 2021 12:30:24 +0000 (GMT)	[thread overview]
Message-ID: <20210302123024.485CC388C01D@sourceware.org> (raw)

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=7a9d006fb51b7889580a07a7fc874a3354c3b9df

commit 7a9d006fb51b7889580a07a7fc874a3354c3b9df
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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
    <https://www.gnu.org/licenses/>.  */
 
-#include <errno.h>
-#include <signal.h>
 #include <sys/socket.h>
-
+/* 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 <bits/socket-constants.h>
+#endif
+#include <time.h>
+#include <sysdep.h>
 #include <socketcall.h>
-#include <kernel-features.h>
-#include <sys/syscall.h>
 
-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
    <https://www.gnu.org/licenses/>.  */
 
-#include <errno.h>
-#include <signal.h>
 #include <sys/socket.h>
-
+/* 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 <bits/socket-constants.h>
+#endif
+#include <time.h>
+#include <sysdep.h>
 #include <socketcall.h>
-#include <kernel-features.h>
-#include <sys/syscall.h>
 
-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


             reply	other threads:[~2021-03-02 12:30 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-02 12:30 Adhemerval Zanella [this message]
  -- strict thread matches above, loose matches on Subject: below --
2021-06-08 20:48 Adhemerval Zanella
2021-05-26 16:24 Adhemerval Zanella
2021-03-05 19:20 Adhemerval Zanella
2021-03-04 17:36 Adhemerval Zanella
2021-03-04 11:28 Adhemerval Zanella
2021-03-01 17:35 Adhemerval Zanella
2021-02-26 20:40 Adhemerval Zanella
2021-02-23 20:38 Adhemerval Zanella
2021-02-23 12:36 Adhemerval Zanella

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210302123024.485CC388C01D@sourceware.org \
    --to=azanella@sourceware.org \
    --cc=glibc-cvs@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).