diff options
author | Stan Shebs <stanshebs@google.com> | 2017-01-12 21:07:13 -0800 |
---|---|---|
committer | Stan Shebs <stanshebs@google.com> | 2017-01-12 21:07:13 -0800 |
commit | 79ab0fcfdacd9af020f5c5c603f8ac2875980736 (patch) | |
tree | 33e7e57a9f421815f9fa5cdb85afc5d1375d1c3d | |
parent | 882f4078757ab035451bca71ec3906c33f48b668 (diff) | |
download | glibc-79ab0fcfdacd9af020f5c5c603f8ac2875980736.zip glibc-79ab0fcfdacd9af020f5c5c603f8ac2875980736.tar.gz glibc-79ab0fcfdacd9af020f5c5c603f8ac2875980736.tar.bz2 |
Fix where out of range data to strftime() causes a segfault (BZ18985, CVE-2015-8776)
-rw-r--r-- | README.google | 6 | ||||
-rw-r--r-- | time/strftime_l.c | 20 | ||||
-rw-r--r-- | time/tst-strftime.c | 52 |
3 files changed, 70 insertions, 8 deletions
diff --git a/README.google b/README.google index 3e1e215..a815388 100644 --- a/README.google +++ b/README.google @@ -629,3 +629,9 @@ posix/fnmatch_loop.c nss/tst-nss-getpwent.c Work around b/34251679 by restricting to nss_files module (stanshebs, google-local) + +time/strftime_l.c +time/tst-strftime.c + Fix where out of range data to strftime() causes a segfault (BZ18985, CVE-2015-8776) + https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=d36c75fc0d44deec29635dd239b0fbd206ca49b7 + (stanshebs, backport) 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 () |