On 2023-07-29 12:44, Pádraig Brady wrote:
I tried a quick build with -D__WORDSIZE_TIME64_COMPAT32=1
which is what glibc uses to force the smaller time types.
However that didn't fix the issue, so I'll need to look a bit more,
and how to get only utmp access restricted to 32 bit types.

I looked into that, and installed the attached patches into Gnulib and Coreutils respectively; these should work around the problem so I'll boldly close the bug report.

These patches are quite a hack, though, and (obviously) stop working after the year 2038.

What's Debian's and/or Fedora's plan for fixing <utmp.h>/<utmpx.h>'s Y2038 bugs? (Or is the idea to remove the <utmp.h></utmpx.h> API before 2038? :-)

See:

https://lwn.net/Articles/925068/

https://sourceware.org/glibc/wiki/Y2038ProofnessDesign#utmp_types_and_APIs
From c408d9a53dbdaf48b555f216e250a2b3b8e48113 Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Sat, 29 Jul 2023 17:06:42 -0700
Subject: [PATCH] readutmp: work around glibc utmpx bug

When compiled with _TIME_BITS=64, glibc <utmpx.h> does not work,
because the files use 32-bit time_t and the code passes this to
the user unmodified, but <utmpx.h> defines a struct with 64-bit
time_t.  Work around this compatibility bug.  Problem reported
by Jakub Wilk via Sven Joachim <https://bugs.gnu.org/64937>.
* lib/readutmp.c (copy_utmp_entry): New function.
(read_utmp): Use it.
---
 ChangeLog                         | 10 +++++++
 doc/glibc-functions/getutmp.texi  | 13 +++++++++
 doc/glibc-functions/getutmpx.texi | 13 +++++++++
 doc/glibc-headers/utmp.texi       | 13 +++++++++
 doc/posix-headers/utmpx.texi      | 13 +++++++++
 doc/year2038.texi                 |  8 ++++++
 lib/readutmp.c                    | 47 ++++++++++++++++++++++++++++++-
 7 files changed, 116 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index 53e22f3c98..aad4e95ef8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2023-07-29  Paul Eggert  <egg...@cs.ucla.edu>
+
+	readutmp: work around glibc utmpx bug
+	When compiled with _TIME_BITS=64, glibc <utmpx.h> does not work,
+	because the files use 32-bit time_t and the code passes this to
+	the user unmodified, but <utmpx.h> defines a struct with 64-bit
+	time_t.  Work around this compatibility bug.
+	* lib/readutmp.c (copy_utmp_entry): New function.
+	(read_utmp): Use it.
+
 2023-07-29  Bruno Haible  <br...@clisp.org>
 
 	wcsrtombs tests: Renumber tests.
diff --git a/doc/glibc-functions/getutmp.texi b/doc/glibc-functions/getutmp.texi
index 2628441e13..b53369a597 100644
--- a/doc/glibc-functions/getutmp.texi
+++ b/doc/glibc-functions/getutmp.texi
@@ -26,4 +26,17 @@ Portability problems not fixed by Gnulib:
 @item
 This function is missing on some platforms:
 FreeBSD 13.0, OpenBSD 6.7, Minix 3.1.8, AIX 5.1, HP-UX 11, Cygwin 2.9, mingw, MSVC 14, Android 9.0.
+@item
+On some platforms, this function does not support timestamps past the
+year 2038:
+glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t}
+was historically 32 bits.
+@item
+On some platforms, this function misbehaves if the @code{year2038} or
+@code{year2038-recommended} modules are used and the program is
+configured without the @option{--disable-year2038} option.
+The @code{readutmp} module works around this problem:
+glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t}
+was historically 32 bits.
+@xref{Avoiding the year 2038 problem}.
 @end itemize
diff --git a/doc/glibc-functions/getutmpx.texi b/doc/glibc-functions/getutmpx.texi
index 0ebc01978b..bee96fc239 100644
--- a/doc/glibc-functions/getutmpx.texi
+++ b/doc/glibc-functions/getutmpx.texi
@@ -26,4 +26,17 @@ Portability problems not fixed by Gnulib:
 @item
 This function is missing on some platforms:
 FreeBSD 13.0, OpenBSD 6.7, Minix 3.1.8, AIX 5.1, HP-UX 11, Cygwin 2.9, mingw, MSVC 14, Android 9.0.
+@item
+On some platforms, this function does not support timestamps past the
+year 2038:
+glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t}
+was historically 32 bits.
+@item
+On some platforms, this function misbehaves if the @code{year2038} or
+@code{year2038-recommended} modules are used and the program is
+configured without the @option{--disable-year2038} option.
+The @code{readutmp} module works around this problem:
+glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t}
+was historically 32 bits.
+@xref{Avoiding the year 2038 problem}.
 @end itemize
diff --git a/doc/glibc-headers/utmp.texi b/doc/glibc-headers/utmp.texi
index d7d1091e14..1e9d3757cb 100644
--- a/doc/glibc-headers/utmp.texi
+++ b/doc/glibc-headers/utmp.texi
@@ -31,4 +31,17 @@ FreeBSD 8.0, OpenBSD 7.2.
 
 Portability problems not fixed by Gnulib:
 @itemize
+@item
+On some platforms, this API does not support timestamps past the
+year 2038:
+glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t}
+was historically 32 bits.
+@item
+On some platforms, this header misbehaves if the @code{year2038} or
+@code{year2038-recommended} modules are used and the program is
+configured without the @option{--disable-year2038} option.
+The @code{readutmp} module works around this problem:
+glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t}
+was historically 32 bits.
+@xref{Avoiding the year 2038 problem}.
 @end itemize
diff --git a/doc/posix-headers/utmpx.texi b/doc/posix-headers/utmpx.texi
index 812544ad70..fd3d4d6ab7 100644
--- a/doc/posix-headers/utmpx.texi
+++ b/doc/posix-headers/utmpx.texi
@@ -14,4 +14,17 @@ Portability problems not fixed by Gnulib:
 @item
 This header file is missing on some platforms:
 FreeBSD 6.0, OpenBSD 6.7, Minix 3.1.8, mingw, MSVC 14, Android 9.0.
+@item
+On some platforms, this API does not support timestamps past the
+year 2038:
+glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t}
+was historically 32 bits.
+@item
+On some platforms, this header misbehaves if the @code{year2038} or
+@code{year2038-recommended} modules are used and the program is
+configured without the @option{--disable-year2038} option.
+The @code{readutmp} module works around this problem:
+glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t}
+was historically 32 bits.
+@xref{Avoiding the year 2038 problem}.
 @end itemize
diff --git a/doc/year2038.texi b/doc/year2038.texi
index 5964601831..4d56f323f1 100644
--- a/doc/year2038.texi
+++ b/doc/year2038.texi
@@ -103,3 +103,11 @@ Cygwin 3.3.6 (2022) and earlier on x86,
 @item
 Haiku/x86.
 @end itemize
+
+If you use the @samp{year2038} or @samp{year2038-recommended} modules,
+and configure to support timestamps after the year 2038,
+your code should not include @samp{<utmp.h>} or @samp{<utmpx.h>}
+directly, because these include files do not work with 64-bit timestamps
+if the platform's @code{time_t} was traditionally 32 bits.
+Your code can instead use the @samp{readutmp} module,
+which works around this problem.
diff --git a/lib/readutmp.c b/lib/readutmp.c
index d282254cdc..cfc8b69c03 100644
--- a/lib/readutmp.c
+++ b/lib/readutmp.c
@@ -86,6 +86,51 @@ desirable_utmp_entry (STRUCT_UTMP const *u, int options)
 
 #ifdef UTMP_NAME_FUNCTION
 
+static void
+copy_utmp_entry (STRUCT_UTMP *dst, STRUCT_UTMP *src)
+{
+#if __GLIBC__ && _TIME_BITS == 64
+  /* Convert from external form in SRC to internal form in DST.
+     It is OK to convert now, rather than earlier, before
+     desirable_utmp_entry was invoked, because desirable_utmp_entry
+     inspects only the leading prefix of the entry, which is the
+     same in both external and internal forms.  */
+
+  /* This is a near-copy of glibc's struct utmpx, which stops working
+     after the year 2038.  Unlike the glibc version, struct utmpx32
+     describes the file format even if time_t is 64 bits.  */
+  struct utmpx32
+  {
+    short int ut_type;			/* Type of login.  */
+    pid_t ut_pid;			/* Process ID of login process.  */
+    char ut_line[sizeof src->ut_line];	/* Devicename.  */
+    char ut_id[sizeof src->ut_id];	/* Inittab ID.  */
+    char ut_user[sizeof src->ut_user];  /* Username.  */
+    char ut_host[sizeof src->ut_host];	/* Hostname for remote login.  */
+    struct __exit_status ut_exit;	/* Exit status of a process marked
+                                           as DEAD_PROCESS.  */
+    /* The fields ut_session and ut_tv must be the same size when compiled
+       32- and 64-bit.  This allows files and shared memory to be shared
+       between 32- and 64-bit applications.  */
+    int ut_session;			/* Session ID, used for windowing.  */
+    struct
+    {
+      int tv_sec;			/* Seconds.  */
+      int tv_usec;			/* Microseconds.  */
+    } ut_tv;				/* Time entry was made.  */
+    int ut_addr_v6[4];			/* Internet address of remote host.  */
+    char ut_reserved[20];		/* Reserved for future use.  */
+  } *s = (struct utmpx32 *) src;
+  memcpy (dst, s, offsetof (struct utmpx32, ut_session));
+  dst->ut_session = s->ut_session;
+  dst->ut_tv.tv_sec = s->ut_tv.tv_sec;
+  dst->ut_tv.tv_usec = s->ut_tv.tv_usec;
+  memcpy (&dst->ut_addr_v6, s->ut_addr_v6, sizeof dst->ut_addr_v6);
+#else
+  *dst = *src;
+#endif
+}
+
 int
 read_utmp (char const *file, size_t *n_entries, STRUCT_UTMP **utmp_buf,
            int options)
@@ -109,7 +154,7 @@ read_utmp (char const *file, size_t *n_entries, STRUCT_UTMP **utmp_buf,
         if (n_read == n_alloc)
           utmp = xpalloc (utmp, &n_alloc, 1, -1, sizeof *utmp);
 
-        utmp[n_read++] = *u;
+        copy_utmp_entry (&utmp[n_read++], u);
       }
 
   END_UTMP_ENT ();
-- 
2.39.2

From 39f5c3f92e920d857d102d5cf090916739d37be8 Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Sat, 29 Jul 2023 17:12:39 -0700
Subject: [PATCH] build: update gnulib submodule to latest

* NEWS: Mention a bug that this fixes.
---
 NEWS   | 4 ++++
 gnulib | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index bd0c59eb5..92e591ee2 100644
--- a/NEWS
+++ b/NEWS
@@ -39,6 +39,10 @@ GNU coreutils NEWS                                    -*- outline -*-
   Previously a "Too many levels of symbolic links" diagnostic was given.
   [This bug was present in "the beginning".]
 
+  pinky, uptime, users, and who no longer misbehave on 32-bit GNU/Linux
+  platforms like x86 and ARM where time_t was historically 32 bits.
+  [bug introduced in coreutils-9.0]
+
   'pr --length=1 --double-space' no longer enters an infinite loop.
   [This bug was present in "the beginning".]
 
diff --git a/gnulib b/gnulib
index a7f1fa01c..c408d9a53 160000
--- a/gnulib
+++ b/gnulib
@@ -1 +1 @@
-Subproject commit a7f1fa01c17b43898c702eff478c4c2b6293e9c7
+Subproject commit c408d9a53dbdaf48b555f216e250a2b3b8e48113
-- 
2.39.2

Reply via email to