From: Paul Pluzhnikov Date: Sat, 26 Sep 2015 20:27:48 +0000 (-0700) Subject: Fix BZ #18985 -- out of range data to strftime() causes a segfault X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fd6e33ebd157966fed025a8cf68f2f0835dcbf02;p=thirdparty%2Fglibc.git Fix BZ #18985 -- out of range data to strftime() causes a segfault (cherry picked from commit d36c75fc0d44deec29635dd239b0fbd206ca49b7) --- diff --git a/ChangeLog b/ChangeLog index 07703537912..871c722510e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2015-09-26 Paul Pluzhnikov + + [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 [BZ #17905] diff --git a/NEWS b/NEWS index ad87a8d6d80..44fe9164cfb 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 dfb7b4c483b..29c7cdd556c 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 374fba42629..af3ff72faf9 100644 --- a/time/tst-strftime.c +++ b/time/tst-strftime.c @@ -4,6 +4,56 @@ #include +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 ()