diff options
author | Steve Dower <steve.dower@microsoft.com> | 2015-09-07 02:20:51 (GMT) |
---|---|---|
committer | Steve Dower <steve.dower@microsoft.com> | 2015-09-07 02:20:51 (GMT) |
commit | e5b5895b5b52ff14093eaababd04ede69e394959 (patch) | |
tree | 02b475de7c082ad699d769702b7f502167b2064d | |
parent | 714e49371b8d73059cf19f92a8566dcd20c6089a (diff) | |
download | cpython-e5b5895b5b52ff14093eaababd04ede69e394959.zip cpython-e5b5895b5b52ff14093eaababd04ede69e394959.tar.gz cpython-e5b5895b5b52ff14093eaababd04ede69e394959.tar.bz2 |
Issue #24917: time_strftime() buffer over-read.
-rw-r--r-- | Lib/test/test_time.py | 13 | ||||
-rw-r--r-- | Misc/NEWS | 2 | ||||
-rw-r--r-- | Modules/timemodule.c | 16 |
3 files changed, 25 insertions, 6 deletions
diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 6334e02..6bcd212 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -174,6 +174,19 @@ class TimeTestCase(unittest.TestCase): def test_strftime_bounding_check(self): self._bounds_checking(lambda tup: time.strftime('', tup)) + def test_strftime_format_check(self): + # Test that strftime does not crash on invalid format strings + # that may trigger a buffer overread. When not triggered, + # strftime may succeed or raise ValueError depending on + # the platform. + for x in [ '', 'A', '%A', '%AA' ]: + for y in range(0x0, 0x10): + for z in [ '%', 'A%', 'AA%', '%A%', 'A%A%', '%#' ]: + try: + time.strftime(x * y + z) + except ValueError: + pass + def test_default_values_for_zero(self): # Make sure that using all zeros uses the proper default # values. No test for daylight savings since strftime() does @@ -20,6 +20,8 @@ Core and Builtins Library ------- +- Issue #24917: time_strftime() buffer over-read. + - Issue #24748: To resolve a compatibility problem found with py2exe and pywin32, imp.load_dynamic() once again ignores previously loaded modules to support Python modules replacing themselves with extension modules. diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 197d2c0..eca67d9 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -610,14 +610,15 @@ time_strftime(PyObject *self, PyObject *args) #if defined(MS_WINDOWS) && !defined(HAVE_WCSFTIME) /* check that the format string contains only valid directives */ - for(outbuf = strchr(fmt, '%'); + for (outbuf = strchr(fmt, '%'); outbuf != NULL; outbuf = strchr(outbuf+2, '%')) { - if (outbuf[1]=='#') + if (outbuf[1] == '#') ++outbuf; /* not documented by python, */ - if ((outbuf[1] == 'y') && buf.tm_year < 0) - { + if (outbuf[1] == '\0') + break; + if ((outbuf[1] == 'y') && buf.tm_year < 0) { PyErr_SetString(PyExc_ValueError, "format %y requires year >= 1900 on Windows"); Py_DECREF(format); @@ -625,10 +626,12 @@ time_strftime(PyObject *self, PyObject *args) } } #elif (defined(_AIX) || defined(sun)) && defined(HAVE_WCSFTIME) - for(outbuf = wcschr(fmt, '%'); + for (outbuf = wcschr(fmt, '%'); outbuf != NULL; outbuf = wcschr(outbuf+2, '%')) { + if (outbuf[1] == L'\0') + break; /* Issue #19634: On AIX, wcsftime("y", (1899, 1, 1, 0, 0, 0, 0, 0, 0)) returns "0/" instead of "99" */ if (outbuf[1] == L'y' && buf.tm_year < 0) { @@ -659,7 +662,8 @@ time_strftime(PyObject *self, PyObject *args) #if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) err = errno; #endif - if (buflen > 0 || i >= 256 * fmtlen) { + if (buflen > 0 || fmtlen == 0 || + (fmtlen > 4 && i >= 256 * fmtlen)) { /* If the buffer is 256 times as long as the format, it's probably not failing for lack of room! More likely, the format yields an empty result, |