* 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(-)
@@ -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. */