Issue #14579: Fix CVE-2012-2135: vulnerability in the utf-16 decoder after error handling.

Patch by Serhiy Storchaka.
This commit is contained in:
Antoine Pitrou 2012-07-21 00:45:14 +02:00
parent ca9652ea5d
commit b4bbee25b1
3 changed files with 50 additions and 35 deletions

View file

@ -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)