commit 8a0200c833f261e8eb456bbc4f0f5449e1a5e367
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
Date:   Tue Mar 18 18:49:21 2025 +0100

    hurd: Make *utime*s catch invalid times [BZ #32802]

diff --git a/sysdeps/mach/hurd/futimens.c b/sysdeps/mach/hurd/futimens.c
index 30ef0a6493..12125299c4 100644
--- a/sysdeps/mach/hurd/futimens.c
+++ b/sysdeps/mach/hurd/futimens.c
@@ -32,7 +32,9 @@ __futimens (int fd, const struct timespec tsp[2])
   struct timespec atime, mtime;
   error_t err;
 
-  utime_ts_from_tspec (tsp, &atime, &mtime);
+  err = utime_ts_from_tspec (tsp, &atime, &mtime);
+  if (err)
+    return err;
 
   err = HURD_DPORT_USE (fd, __file_utimens (port, atime, mtime));
 
@@ -40,7 +42,9 @@ __futimens (int fd, const struct timespec tsp[2])
     {
       time_value_t atim, mtim;
 
-      utime_tvalue_from_tspec (tsp, &atim, &mtim);
+      err = utime_tvalue_from_tspec (tsp, &atim, &mtim);
+      if (err)
+	return err;
 
       err = HURD_DPORT_USE (fd, __file_utimes (port, atim, mtim));
   }
diff --git a/sysdeps/mach/hurd/futimes.c b/sysdeps/mach/hurd/futimes.c
index 20f47f3d28..97385d7dd0 100644
--- a/sysdeps/mach/hurd/futimes.c
+++ b/sysdeps/mach/hurd/futimes.c
@@ -32,7 +32,9 @@ __futimes (int fd, const struct timeval tvp[2])
   struct timespec atime, mtime;
   error_t err;
 
-  utime_ts_from_tval (tvp, &atime, &mtime);
+  err = utime_ts_from_tval (tvp, &atime, &mtime);
+  if (err)
+    return err;
 
   err = HURD_DPORT_USE (fd, __file_utimens (port, atime, mtime));
 
@@ -40,7 +42,9 @@ __futimes (int fd, const struct timeval tvp[2])
     {
       time_value_t atim, mtim;
 
-      utime_tvalue_from_tval (tvp, &atim, &mtim);
+      err = utime_tvalue_from_tval (tvp, &atim, &mtim);
+      if (err)
+	return err;
 
       err = HURD_DPORT_USE (fd, __file_utimes (port, atim, mtim));
     }
diff --git a/sysdeps/mach/hurd/utime-helper.c b/sysdeps/mach/hurd/utime-helper.c
index d88bccd786..6afa871197 100644
--- a/sysdeps/mach/hurd/utime-helper.c
+++ b/sysdeps/mach/hurd/utime-helper.c
@@ -21,8 +21,14 @@
 #include <stddef.h>
 #include <sys/time.h>
 
+static inline bool
+check_tval (const struct timeval *tvp)
+{
+  return tvp->tv_usec >= 0 && tvp->tv_usec < USEC_PER_SEC;
+}
+
 /* Initializes atime/mtime timespec structures from an array of timeval.  */
-static inline void
+static inline error_t
 utime_ts_from_tval (const struct timeval tvp[2],
                     struct timespec *atime, struct timespec *mtime)
 {
@@ -37,13 +43,19 @@ utime_ts_from_tval (const struct timeval tvp[2],
     }
   else
     {
+      if (!check_tval (&tvp[0]))
+	return EINVAL;
+      if (!check_tval (&tvp[1]))
+	return EINVAL;
+
       TIMEVAL_TO_TIMESPEC (&tvp[0], atime);
       TIMEVAL_TO_TIMESPEC (&tvp[1], mtime);
     }
+  return 0;
 }
 
 /* Initializes atime/mtime time_value_t structures from an array of timeval.  */
-static inline void
+static inline error_t
 utime_tvalue_from_tval (const struct timeval tvp[2],
                         time_value_t *atime, time_value_t *mtime)
 {
@@ -53,11 +65,17 @@ utime_tvalue_from_tval (const struct timeval tvp[2],
     atime->microseconds = mtime->microseconds = -1;
   else
     {
+      if (!check_tval (&tvp[0]))
+	return EINVAL;
+      if (!check_tval (&tvp[1]))
+	return EINVAL;
+
       atime->seconds = tvp[0].tv_sec;
       atime->microseconds = tvp[0].tv_usec;
       mtime->seconds = tvp[1].tv_sec;
       mtime->microseconds = tvp[1].tv_usec;
     }
+  return 0;
 }
 
 /* Changes the access time of the file behind PORT using a timeval array.  */
@@ -67,7 +85,9 @@ hurd_futimes (const file_t port, const struct timeval tvp[2])
   error_t err;
   struct timespec atime, mtime;
 
-  utime_ts_from_tval (tvp, &atime, &mtime);
+  err = utime_ts_from_tval (tvp, &atime, &mtime);
+  if (err)
+    return err;
 
   err = __file_utimens (port, atime, mtime);
 
@@ -75,7 +95,9 @@ hurd_futimes (const file_t port, const struct timeval tvp[2])
     {
       time_value_t atim, mtim;
 
-      utime_tvalue_from_tval (tvp, &atim, &mtim);
+      err = utime_tvalue_from_tval (tvp, &atim, &mtim);
+      if (err)
+	return err;
 
       err = __file_utimes (port, atim, mtim);
     }
@@ -83,8 +105,16 @@ hurd_futimes (const file_t port, const struct timeval tvp[2])
   return err;
 }
 
+static inline bool
+check_tspec (const struct timespec *tsp)
+{
+  return tsp->tv_nsec == UTIME_NOW
+      || tsp->tv_nsec == UTIME_OMIT
+      || tsp->tv_nsec >= 0 && tsp->tv_nsec < NSEC_PER_SEC;
+}
+
 /* Initializes atime/mtime timespec structures from an array of timespec.  */
-static inline void
+static inline error_t
 utime_ts_from_tspec (const struct timespec tsp[2],
                      struct timespec *atime, struct timespec *mtime)
 {
@@ -99,13 +129,19 @@ utime_ts_from_tspec (const struct timespec tsp[2],
     }
   else
     {
+      if (!check_tspec (&tsp[0]))
+	return EINVAL;
+      if (!check_tspec (&tsp[1]))
+	return EINVAL;
+
       *atime = tsp[0];
       *mtime = tsp[1];
     }
+  return 0;
 }
 
 /* Initializes atime/mtime time_value_t structures from an array of timespec.  */
-static inline void
+static inline error_t
 utime_tvalue_from_tspec (const struct timespec tsp[2],
                          time_value_t *atime, time_value_t *mtime)
 {
@@ -115,6 +151,11 @@ utime_tvalue_from_tspec (const struct timespec tsp[2],
     atime->microseconds = mtime->microseconds = -1;
   else
     {
+      if (!check_tspec (&tsp[0]))
+	return EINVAL;
+      if (!check_tspec (&tsp[1]))
+	return EINVAL;
+
       if (tsp[0].tv_nsec == UTIME_NOW)
 	atime->microseconds = -1;
       else if (tsp[0].tv_nsec == UTIME_OMIT)
@@ -128,6 +169,7 @@ utime_tvalue_from_tspec (const struct timespec tsp[2],
       else
 	TIMESPEC_TO_TIME_VALUE (mtime, &(tsp[1]));
     }
+  return 0;
 }
 
 /* Changes the access time of the file behind PORT using a timespec array.  */
@@ -137,7 +179,9 @@ hurd_futimens (const file_t port, const struct timespec tsp[2])
   error_t err;
   struct timespec atime, mtime;
 
-  utime_ts_from_tspec (tsp, &atime, &mtime);
+  err = utime_ts_from_tspec (tsp, &atime, &mtime);
+  if (err)
+    return err;
 
   err = __file_utimens (port, atime, mtime);
 
@@ -145,7 +189,9 @@ hurd_futimens (const file_t port, const struct timespec tsp[2])
     {
       time_value_t atim, mtim;
 
-      utime_tvalue_from_tspec (tsp, &atim, &mtim);
+      err = utime_tvalue_from_tspec (tsp, &atim, &mtim);
+      if (err)
+	return err;
 
       err = __file_utimes (port, atim, mtim);
     }
