[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] readutmp: work around glibc utmpx bug
From: |
Paul Eggert |
Subject: |
[PATCH] readutmp: work around glibc utmpx bug |
Date: |
Sat, 29 Jul 2023 17:34:39 -0700 |
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 <eggert@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 <bruno@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
- [PATCH] readutmp: work around glibc utmpx bug,
Paul Eggert <=