summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Dower <steve.dower@microsoft.com>2015-09-07 02:20:51 (GMT)
committerSteve Dower <steve.dower@microsoft.com>2015-09-07 02:20:51 (GMT)
commite5b5895b5b52ff14093eaababd04ede69e394959 (patch)
tree02b475de7c082ad699d769702b7f502167b2064d
parent714e49371b8d73059cf19f92a8566dcd20c6089a (diff)
downloadcpython-e5b5895b5b52ff14093eaababd04ede69e394959.zip
cpython-e5b5895b5b52ff14093eaababd04ede69e394959.tar.gz
cpython-e5b5895b5b52ff14093eaababd04ede69e394959.tar.bz2
Issue #24917: time_strftime() buffer over-read.
-rw-r--r--Lib/test/test_time.py13
-rw-r--r--Misc/NEWS2
-rw-r--r--Modules/timemodule.c16
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
diff --git a/Misc/NEWS b/Misc/NEWS
index b28aa19..b1f1498 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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,