[32/59] Reject invalid TZ strings in TZif files

Message ID 20250105055750.1668721-33-eggert@cs.ucla.edu (mailing list archive)
State New
Headers
Series time: sync mktime from Gnulib |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent

Commit Message

Paul Eggert Jan. 5, 2025, 5:57 a.m. UTC
  Previously, the code could have had quirky behavior if a TZif
file's TZ string was corrupted.  Now, the code reliably ignores
such a string.
* time/tzfile.c (__tzfile_compute): If the proleptic TZ string
is invalid, do not use it.
* time/tzset.c (__tzset_parse_tz): Return a success indication.
Do not try to parse DST rule if there is no DST.
---
 time/tzfile.c |  5 +++--
 time/tzset.c  | 15 ++++++---------
 time/tzset.h  |  2 +-
 3 files changed, 10 insertions(+), 12 deletions(-)
  

Patch

diff --git a/time/tzfile.c b/time/tzfile.c
index d30faedfa2..dae6b2b613 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -620,8 +620,9 @@  __tzfile_compute (__time64_t timer, int use_localtime,
 	      goto found;
 	    }
 
-	  /* Parse the proleptic TZ string.  */
-	  __tzset_parse_tz (tzspec);
+	  /* Parse the proleptic TZ string.  If this fails do not use it.  */
+	  if (__glibc_unlikely (! __tzset_parse_tz (tzspec)))
+	    goto use_last;
 
 	  /* Convert to broken down structure.  If this fails do not
 	     use the string.  */
diff --git a/time/tzset.c b/time/tzset.c
index 7fdce9de7b..e4fbf729b8 100644
--- a/time/tzset.c
+++ b/time/tzset.c
@@ -350,7 +350,7 @@  parse_rule (const char **tzp, int whichrule)
 }
 
 /* Parse a proleptic TZ string.  */
-void
+bool
 __tzset_parse_tz (const char *tz)
 {
   /* Clear out old state and reset to UTC.  */
@@ -360,17 +360,13 @@  __tzset_parse_tz (const char *tz)
   tz_rules[0].name = tz_rules[1].name = "UTC";
 
   /* Get the standard time zone abbreviations.  */
-  if (parse_tzname (&tz, 0) && parse_offset (&tz, 0))
+  bool ok = parse_tzname (&tz, 0) && parse_offset (&tz, 0);
+  if (ok)
     {
       /* Get the DST time zone abbreviation (if any).  */
       if (*tz != '\0')
-	{
-	  if (parse_tzname (&tz, 1))
-	    parse_offset (&tz, 1);
-	  /* Figure out the standard <-> DST rules.  */
-	  if (parse_rule (&tz, 0))
-	    parse_rule (&tz, 1);
-	}
+	ok = (parse_tzname (&tz, 1) && parse_offset (&tz, 1)
+	      && parse_rule (&tz, 0) && parse_rule (&tz, 1));
       else
 	{
 	  /* There is no DST.  */
@@ -380,6 +376,7 @@  __tzset_parse_tz (const char *tz)
     }
 
   update_vars ();
+  return ok;
 }
 
 /* Interpret the TZ envariable.  */
diff --git a/time/tzset.h b/time/tzset.h
index 3687c044e3..61c85fba75 100644
--- a/time/tzset.h
+++ b/time/tzset.h
@@ -14,7 +14,7 @@  extern void __tzfile_read (const char *file) attribute_hidden;
 extern void __tzfile_compute (__time64_t timer, int use_localtime,
 			      int *leap_correct, bool *leap_hit,
 			      struct tm *tp) attribute_hidden;
-extern void __tzset_parse_tz (const char *tz) attribute_hidden;
+extern bool __tzset_parse_tz (const char *tz) attribute_hidden;
 extern void __tz_compute (__time64_t timer, struct tm *tm)
   __THROW attribute_hidden;