]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Fix BZ #18985 -- out of range data to strftime() causes a segfault
authorPaul Pluzhnikov <ppluzhnikov@google.com>
Sat, 26 Sep 2015 20:27:48 +0000 (13:27 -0700)
committerPaul Pluzhnikov <ppluzhnikov@google.com>
Sat, 26 Sep 2015 20:27:48 +0000 (13:27 -0700)
ChangeLog
NEWS
time/strftime_l.c
time/tst-strftime.c

index e70cd2fbdc99caa310d3df4fefa37008924fb3d1..b13afb734a1b3acf8ca2b6e22200dce640e86b4d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2015-09-26  Paul Pluzhnikov  <ppluzhnikov@google.com>
+
+       [BZ #18985]
+       * time/strftime_l.c (a_wkday, f_wkday, a_month, f_month): Range check.
+       (__strftime_internal): Likewise.
+       * time/tst-strftime.c (do_bz18985): New test.
+       (do_test): Call it.
+
 2015-09-26  Joseph Myers  <joseph@codesourcery.com>
 
        [BZ #18956]
diff --git a/NEWS b/NEWS
index aa9ca4bc9dcd93e6188dd00dd23255bf2d6c2af3..da9c8dfe921c837f0dd0dd07b4f7b04e2e4da5e3 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -16,7 +16,7 @@ Version 2.23
   18618, 18647, 18661, 18674, 18675, 18681, 18757, 18778, 18781, 18787,
   18789, 18790, 18795, 18796, 18803, 18820, 18823, 18824, 18825, 18857,
   18863, 18870, 18872, 18873, 18875, 18887, 18921, 18951, 18952, 18956,
-  18961, 18966, 18967, 18970, 18977, 18980, 18981, 19003.
+  18961, 18966, 18967, 18970, 18977, 18980, 18981, 18985, 19003.
 
 * The obsolete header <regexp.h> has been removed.  Programs that require
   this header must be updated to use <regex.h> instead.
index b48ef340342817840e5dc22c4223493654e9a344..4eb647c9761b7de6f16d67d009f9a86c5a1e217c 100644 (file)
@@ -510,13 +510,17 @@ __strftime_internal (s, maxsize, format, tp, tzset_called ut_argument
      only a few elements.  Dereference the pointers only if the format
      requires this.  Then it is ok to fail if the pointers are invalid.  */
 # define a_wkday \
-  ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
+  ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6                             \
+                    ? "?" : _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday)))
 # define f_wkday \
-  ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
+  ((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6                             \
+                    ? "?" : _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday)))
 # define a_month \
-  ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
+  ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11                      \
+                    ? "?" : _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon)))
 # define f_month \
-  ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
+  ((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11                      \
+                    ? "?" : _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon)))
 # define ampm \
   ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11                   \
                                 ? NLW(PM_STR) : NLW(AM_STR)))
@@ -526,8 +530,10 @@ __strftime_internal (s, maxsize, format, tp, tzset_called ut_argument
 # define ap_len STRLEN (ampm)
 #else
 # if !HAVE_STRFTIME
-#  define f_wkday (weekday_name[tp->tm_wday])
-#  define f_month (month_name[tp->tm_mon])
+#  define f_wkday (tp->tm_wday < 0 || tp->tm_wday > 6  \
+                  ? "?" : weekday_name[tp->tm_wday])
+#  define f_month (tp->tm_mon < 0 || tp->tm_mon > 11   \
+                  ? "?" : month_name[tp->tm_mon])
 #  define a_wkday f_wkday
 #  define a_month f_month
 #  define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
@@ -1321,7 +1327,7 @@ __strftime_internal (s, maxsize, format, tp, tzset_called ut_argument
                  *tzset_called = true;
                }
 # endif
-             zone = tzname[tp->tm_isdst];
+             zone = tp->tm_isdst <= 1 ? tzname[tp->tm_isdst] : "?";
            }
 #endif
          if (! zone)
index 374fba426293b2cc43f0efb0b36f0473c9e2c9c7..af3ff72faf9588126fb269b0e9080357c32b5fcb 100644 (file)
@@ -4,6 +4,56 @@
 #include <time.h>
 
 
+static int
+do_bz18985 (void)
+{
+  char buf[1000];
+  struct tm ttm;
+  int rc, ret = 0;
+
+  memset (&ttm, 1, sizeof (ttm));
+  ttm.tm_zone = NULL;  /* Dereferenced directly if non-NULL.  */
+  rc = strftime (buf, sizeof (buf), "%a %A %b %B %c %z %Z", &ttm);
+
+  if (rc == 66)
+    {
+      const char expected[]
+       = "? ? ? ? ? ? 16843009 16843009:16843009:16843009 16844909 +467836 ?";
+      if (0 != strcmp (buf, expected))
+       {
+         printf ("expected:\n  %s\ngot:\n  %s\n", expected, buf);
+         ret += 1;
+       }
+    }
+  else
+    {
+      printf ("expected 66, got %d\n", rc);
+      ret += 1;
+    }
+
+  /* Check negative values as well.  */
+  memset (&ttm, 0xFF, sizeof (ttm));
+  ttm.tm_zone = NULL;  /* Dereferenced directly if non-NULL.  */
+  rc = strftime (buf, sizeof (buf), "%a %A %b %B %c %z %Z", &ttm);
+
+  if (rc == 30)
+    {
+      const char expected[] = "? ? ? ? ? ? -1 -1:-1:-1 1899  ";
+      if (0 != strcmp (buf, expected))
+       {
+         printf ("expected:\n  %s\ngot:\n  %s\n", expected, buf);
+         ret += 1;
+       }
+    }
+  else
+    {
+      printf ("expected 30, got %d\n", rc);
+      ret += 1;
+    }
+
+  return ret;
+}
+
 static struct
 {
   const char *fmt;
@@ -104,7 +154,7 @@ do_test (void)
        }
     }
 
-  return result;
+  return result + do_bz18985 ();
 }
 
 #define TEST_FUNCTION do_test ()