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 e70cd2f..b13afb7 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 aa9ca4b..da9c8df 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 b48ef34..4eb647c 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 374fba4..af3ff72 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 ()