The following test fails on GNU/Hurd:
test-utimens.h:80: assertion 'func (BASE "file", ts) == -1' failed
FAIL test-utimensat (exit status: 134)
This is because utimensat does not validate the tv_nsec fields of it's
arguments.
I have reported this bug to the hurd component of glibc [1]. And pushed
the attached patch to fix it in Gnulib.
Collin
[1] https://sourceware.org/bugzilla/show_bug.cgi?id=32802
>From 381815da7f8d319e7dd9a59509f901fc9948918c Mon Sep 17 00:00:00 2001
From: Collin Funk <[email protected]>
Date: Mon, 17 Mar 2025 21:16:22 -0700
Subject: [PATCH] utimensat: Work around a GNU/Hurd bug.
* lib/utimensat.c (rpl_utimensat) [__gnu_hurd__]: Check for out of range
tv_nsec values.
* m4/utimensat.m4 (gl_FUNC_UTIMENSAT): Likewise. Guess that utimensat
doesn't work on GNU/Hurd.
* doc/posix-functions/utimensat.texi: Mention the bug.
---
ChangeLog | 9 +++++++++
doc/posix-functions/utimensat.texi | 3 ++-
lib/utimensat.c | 7 +++++--
m4/utimensat.m4 | 24 +++++++++++++++++++++++-
4 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index b653fc2914..6cf9c5127b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2025-03-17 Collin Funk <[email protected]>
+
+ utimensat: Work around a GNU/Hurd bug.
+ * lib/utimensat.c (rpl_utimensat) [__gnu_hurd__]: Check for out of range
+ tv_nsec values.
+ * m4/utimensat.m4 (gl_FUNC_UTIMENSAT): Likewise. Guess that utimensat
+ doesn't work on GNU/Hurd.
+ * doc/posix-functions/utimensat.texi: Mention the bug.
+
2025-03-13 Collin Funk <[email protected]>
vma-iter: Detect executable memory segments on Haiku (regr. 2011-01-25).
diff --git a/doc/posix-functions/utimensat.texi b/doc/posix-functions/utimensat.texi
index 81e294234a..97021d279b 100644
--- a/doc/posix-functions/utimensat.texi
+++ b/doc/posix-functions/utimensat.texi
@@ -36,7 +36,8 @@ @node utimensat
@item
Out-of-range values of @code{tv_nsec} do not lead to a failure on some
platforms:
-Linux kernel 2.6.22.19 on hppa, NetBSD 10.0.
+@c https://sourceware.org/bugzilla/show_bug.cgi?id=32802
+Linux kernel 2.6.22.19 on hppa, NetBSD 10.0, GNU/Hurd.
@item
On some platforms, this function mis-handles a trailing slash:
AIX 7.2.
diff --git a/lib/utimensat.c b/lib/utimensat.c
index 227474fdaa..ca1d39e590 100644
--- a/lib/utimensat.c
+++ b/lib/utimensat.c
@@ -136,8 +136,9 @@ rpl_utimensat (int fd, char const *file, struct timespec const times[2],
}
# endif
# endif
-# if defined __APPLE__ && defined __MACH__
- /* macOS 10.13 does not reject invalid tv_nsec values either. */
+# if (defined __APPLE__ && defined __MACH__) || defined __gnu_hurd__
+ /* macOS 10.13 and GNU Hurd do not reject invalid tv_nsec values
+ either. */
if (times
&& ((times[0].tv_nsec != UTIME_OMIT
&& times[0].tv_nsec != UTIME_NOW
@@ -151,6 +152,7 @@ rpl_utimensat (int fd, char const *file, struct timespec const times[2],
errno = EINVAL;
return -1;
}
+# if defined __APPLE__ && defined __MACH__
size_t len = strlen (file);
if (len > 0 && file[len - 1] == '/')
{
@@ -163,6 +165,7 @@ rpl_utimensat (int fd, char const *file, struct timespec const times[2],
return -1;
}
}
+# endif
# endif
result = utimensat (fd, file, times, flag);
/* Linux kernel 2.6.25 has a bug where it returns EINVAL for
diff --git a/m4/utimensat.m4 b/m4/utimensat.m4
index 8753e1cb29..1a3802ad28 100644
--- a/m4/utimensat.m4
+++ b/m4/utimensat.m4
@@ -73,6 +73,25 @@ AC_DEFUN([gl_FUNC_UTIMENSAT]
else if (st.st_ctime < st.st_atime)
result |= 64;
}
+ enum
+ {
+ BILLION = 1000 * 1000 * 1000,
+ /* Bogus positive and negative tv_nsec values closest to valid
+ range, but without colliding with UTIME_NOW or UTIME_OMIT. */
+ UTIME_BOGUS_POS = BILLION + ((UTIME_NOW == BILLION || UTIME_OMIT == BILLION)
+ ? (1 + (UTIME_NOW == BILLION + 1)
+ + (UTIME_OMIT == BILLION + 1))
+ : 0)
+ };
+ {
+ struct timespec ts[2];
+ ts[0].tv_sec = 1;
+ ts[0].tv_nsec = UTIME_BOGUS_POS;
+ ts[1].tv_sec = 1;
+ ts[1].tv_nsec = 0;
+ if (utimensat (AT_FDCWD, f, ts, 0) == 0)
+ result |= 128;
+ }
return result;
]])],
[gl_cv_func_utimensat_works=yes],
@@ -83,8 +102,11 @@ AC_DEFUN([gl_FUNC_UTIMENSAT]
],
[case "$host_os" in
# Guess yes on Linux or glibc systems.
- linux-* | linux | *-gnu* | gnu*)
+ linux*)
gl_cv_func_utimensat_works="guessing yes" ;;
+ # Guess no on GNU/Hurd.
+ gnu*)
+ gl_cv_func_utimensat_works="guessing no" ;;
# Guess yes on systems that emulate the Linux system calls.
midipix*)
gl_cv_func_utimensat_works="guessing yes" ;;
--
2.48.1