diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2012-07-20 22:45:14 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2012-07-20 22:45:14 (GMT) |
commit | b4bbee25b1e3f4bccac222f806b3138fb72439d6 (patch) | |
tree | 586129fbe8b38a553772635efa1ff753e5c7be70 /Objects | |
parent | ca9652ea5d1d9ebddd1acf6abbbf3751bc366a44 (diff) | |
download | cpython-b4bbee25b1e3f4bccac222f806b3138fb72439d6.zip cpython-b4bbee25b1e3f4bccac222f806b3138fb72439d6.tar.gz cpython-b4bbee25b1e3f4bccac222f806b3138fb72439d6.tar.bz2 |
Issue #14579: Fix CVE-2012-2135: vulnerability in the utf-16 decoder after error handling.
Patch by Serhiy Storchaka.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/unicodeobject.c | 52 |
1 files changed, 21 insertions, 31 deletions
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index cd17789..d5ef87f 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3425,7 +3425,7 @@ PyUnicode_DecodeUTF16Stateful(const char *s, /* Unpack UTF-16 encoded data */ p = unicode->str; q = (unsigned char *)s; - e = q + size - 1; + e = q + size; if (byteorder) bo = *byteorder; @@ -3476,8 +3476,20 @@ PyUnicode_DecodeUTF16Stateful(const char *s, #endif aligned_end = (const unsigned char *) ((size_t) e & ~LONG_PTR_MASK); - while (q < e) { + while (1) { Py_UNICODE ch; + if (e - q < 2) { + /* remaining byte at the end? (size should be even) */ + if (q == e || consumed) + break; + errmsg = "truncated data"; + startinpos = ((const char *)q) - starts; + endinpos = ((const char *)e) - starts; + outpos = p - PyUnicode_AS_UNICODE(unicode); + goto utf16Error; + /* The remaining input chars are ignored if the callback + chooses to skip the input */ + } /* First check for possible aligned read of a C 'long'. Unaligned reads are more expensive, better to defer to another iteration. */ if (!((size_t) q & LONG_PTR_MASK)) { @@ -3546,8 +3558,8 @@ PyUnicode_DecodeUTF16Stateful(const char *s, } p = _p; q = _q; - if (q >= e) - break; + if (e - q < 2) + continue; } ch = (q[ihi] << 8) | q[ilo]; @@ -3559,10 +3571,10 @@ PyUnicode_DecodeUTF16Stateful(const char *s, } /* UTF-16 code pair: */ - if (q > e) { + if (e - q < 2) { errmsg = "unexpected end of data"; startinpos = (((const char *)q) - 2) - starts; - endinpos = ((const char *)e) + 1 - starts; + endinpos = ((const char *)e) - starts; goto utf16Error; } if (0xD800 <= ch && ch <= 0xDBFF) { @@ -3606,31 +3618,9 @@ PyUnicode_DecodeUTF16Stateful(const char *s, &outpos, &p)) goto onError; - } - /* remaining byte at the end? (size should be even) */ - if (e == q) { - if (!consumed) { - errmsg = "truncated data"; - startinpos = ((const char *)q) - starts; - endinpos = ((const char *)e) + 1 - starts; - outpos = p - PyUnicode_AS_UNICODE(unicode); - if (unicode_decode_call_errorhandler( - errors, - &errorHandler, - "utf16", errmsg, - &starts, - (const char **)&e, - &startinpos, - &endinpos, - &exc, - (const char **)&q, - &unicode, - &outpos, - &p)) - goto onError; - /* The remaining input chars are ignored if the callback - chooses to skip the input */ - } + /* Update data because unicode_decode_call_errorhandler might have + changed the input object. */ + aligned_end = (const unsigned char *) ((size_t) e & ~LONG_PTR_MASK); } if (byteorder) |