[COMMITTED 2.19] Fix BZ #18985 -- out of range data to strftime() causes a segfault
Aurelien Jarno
aurelien@aurel32.net
Fri Jan 1 00:00:00 GMT 2016
From: Paul Pluzhnikov <ppluzhnikov@google.com>
(cherry picked from commit d36c75fc0d44deec29635dd239b0fbd206ca49b7)
---
ChangeLog | 8 ++++++++
NEWS | 2 +-
time/strftime_l.c | 20 +++++++++++++-------
time/tst-strftime.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 73 insertions(+), 9 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 0770353..871c722 100644
--- 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-08-08 Paul Pluzhnikov <ppluzhnikov@google.com>
[BZ #17905]
diff --git a/NEWS b/NEWS
index ad87a8d..44fe916 100644
--- a/NEWS
+++ b/NEWS
@@ -12,7 +12,7 @@ Version 2.19.1
15946, 16545, 16574, 16623, 16657, 16695, 16743, 16758, 16759, 16760,
16878, 16882, 16885, 16916, 16932, 16943, 16958, 17048, 17062, 17069,
17079, 17137, 17153, 17213, 17263, 17269, 17325, 17555, 17905, 18007,
- 18032, 18287.
+ 18032, 18287, 18905.
* A buffer overflow in gethostbyname_r and related functions performing DNS
requests has been fixed. If the NSS functions were called with a
diff --git a/time/strftime_l.c b/time/strftime_l.c
index dfb7b4c..29c7cdd 100644
--- a/time/strftime_l.c
+++ b/time/strftime_l.c
@@ -509,13 +509,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)))
@@ -525,8 +529,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))
@@ -1320,7 +1326,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)
diff --git a/time/tst-strftime.c b/time/tst-strftime.c
index 374fba4..af3ff72 100644
--- a/time/tst-strftime.c
+++ b/time/tst-strftime.c
@@ -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 ()
--
2.7.0.rc3
More information about the Libc-stable
mailing list