[33/59] Reject TZif files containing '\0' in TZ string

Message ID 20250105055750.1668721-34-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
  * time/tzfile.c (__tzfile_read): Don't allow TZif strings
that contain '\0'.  If a TZif file is longer than needed,
perhaps due to future TZif format, don't bother reading
the excess data.
---
 time/tzfile.c | 39 ++++++++++++++++++++++++---------------
 1 file changed, 24 insertions(+), 15 deletions(-)
  

Patch

diff --git a/time/tzfile.c b/time/tzfile.c
index dae6b2b613..744c7690ab 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -258,7 +258,7 @@  __tzfile_read (const char *file)
       goto read_again;
     }
 
-  /* Compute the size of the proleptic time zone specification in the
+  /* Compute a bound on the size of the proleptic time zone specification in the
      file.  This includes the trailing but not the leading newline.  */
   size_t tzspec_size;
   if (trans_width == 8)
@@ -472,24 +472,33 @@  __tzfile_read (const char *file)
     types[i++].isutc = 0;
 
   /* Read the proleptic TZ information if possible.  */
-  if (tzspec != NULL)
+  if (tzspec_size != 0)
     {
-      char *nl;
-      assert (tzspec_size > 0);
-      /* Skip the leading newline, then grab everything up to the next
-	 newline; ignore everything after that.  */
-      if (__getc_unlocked (f) == '\n'
-	  && __fread_unlocked (tzspec, 1, tzspec_size, f) == tzspec_size
-	  && (nl = memchr (tzspec, '\n', tzspec_size)) != NULL)
-	*nl = '\0';
-      else
+      /* Don't use a TZ string not preceded by newline.  */
+      if (__getc_unlocked (f) != '\n')
+	goto lose;
+      size_t len = 0;
+      /* Grab everything up to the next newline.  Ignore the remaining
+	 part of the file as it may be a later TZif version.  */
+      for (int ch; (ch = __getc_unlocked (f)) != '\n'; )
+	{
+	  /* Don't use a truncated TZ string, or one containing '\0'.  */
+	  if (ch <= 0)
+	    goto lose;
+
+	  tzspec[len++] = ch;
+
+	  /* Don't use a TZ string that lacks a trailing newline.  */
+	  if (len == tzspec_size)
+	    goto lose;
+	}
+      tzspec[len] = '\0';
+
+      /* Don't use an empty TZ string.  */
+      if (len == 0)
 	tzspec = NULL;
     }
 
-  /* Don't use an empty TZ string.  */
-  if (tzspec != NULL && tzspec[0] == '\0')
-    tzspec = NULL;
-
   fclose (f);
 
   /* First "register" all time zone abbreviations.  */