Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP1:GA
icu.14722
icu-CVE-2020-10531.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File icu-CVE-2020-10531.patch of Package icu.14722
diff -Nura icu/source/common/putil.cpp icu_new/source/common/putil.cpp --- icu/source/common/putil.cpp 2013-10-05 04:49:20.000000000 +0800 +++ icu_new/source/common/putil.cpp 2020-04-14 17:45:09.237000000 +0800 @@ -535,6 +535,30 @@ return (x > y ? y : x); } +#include <iostream> + +U_CAPI UBool U_EXPORT2 +uprv_add32_overflow(int32_t a, int32_t b, int32_t* res) { + // NOTE: Some compilers (GCC, Clang) have primitives available, like __builtin_add_overflow. + // This function could be optimized by calling one of those primitives. + auto a64 = static_cast<int64_t>(a); + auto b64 = static_cast<int64_t>(b); + int64_t res64 = a64 + b64; + *res = static_cast<int32_t>(res64); + return res64 != *res; +} + +U_CAPI UBool U_EXPORT2 +uprv_mul32_overflow(int32_t a, int32_t b, int32_t* res) { + // NOTE: Some compilers (GCC, Clang) have primitives available, like __builtin_mul_overflow. + // This function could be optimized by calling one of those primitives. + auto a64 = static_cast<int64_t>(a); + auto b64 = static_cast<int64_t>(b); + int64_t res64 = a64 * b64; + *res = static_cast<int32_t>(res64); + return res64 != *res; +} + /** * Truncates the given double. * trunc(3.3) = 3.0, trunc (-3.3) = -3.0 diff -Nura icu/source/common/putilimp.h icu_new/source/common/putilimp.h --- icu/source/common/putilimp.h 2013-10-05 04:49:30.000000000 +0800 +++ icu_new/source/common/putilimp.h 2020-04-14 22:01:40.868000000 +0800 @@ -392,6 +392,32 @@ */ U_INTERNAL double U_EXPORT2 uprv_round(double x); +/** + * Adds the signed integers a and b, storing the result in res. + * Checks for signed integer overflow. + * Similar to the GCC/Clang extension __builtin_add_overflow + * + * @param a The first operand. + * @param b The second operand. + * @param res a + b + * @return true if overflow occurred; false if no overflow occurred. + * @internal + */ +U_INTERNAL UBool U_EXPORT2 uprv_add32_overflow(int32_t a, int32_t b, int32_t* res); + +/** + * Multiplies the signed integers a and b, storing the result in res. + * Checks for signed integer overflow. + * Similar to the GCC/Clang extension __builtin_mul_overflow + * + * @param a The first multiplicand. + * @param b The second multiplicand. + * @param res a * b + * @return true if overflow occurred; false if no overflow occurred. + * @internal + */ +U_INTERNAL UBool U_EXPORT2 uprv_mul32_overflow(int32_t a, int32_t b, int32_t* res); + #if 0 /** * Returns the number of digits after the decimal point in a double number x. diff -Nura icu/source/common/unicode/unistr.h icu_new/source/common/unicode/unistr.h --- icu/source/common/unicode/unistr.h 2013-10-05 04:49:10.000000000 +0800 +++ icu_new/source/common/unicode/unistr.h 2020-04-13 10:48:15.740000000 +0800 @@ -3359,6 +3359,9 @@ int32_t srcStart, int32_t srcLength); + UnicodeString& doAppend(const UnicodeString& src, int32_t srcStart, int32_t srcLength); + UnicodeString& doAppend(const UChar *srcChars, int32_t srcStart, int32_t srcLength); + UnicodeString& doReverse(int32_t start, int32_t length); @@ -4337,30 +4340,30 @@ UnicodeString::append(const UnicodeString& srcText, int32_t srcStart, int32_t srcLength) -{ return doReplace(length(), 0, srcText, srcStart, srcLength); } +{ return doAppend(srcText, srcStart, srcLength); } inline UnicodeString& UnicodeString::append(const UnicodeString& srcText) -{ return doReplace(length(), 0, srcText, 0, srcText.length()); } +{ return doAppend(srcText, 0, srcText.length()); } inline UnicodeString& UnicodeString::append(const UChar *srcChars, int32_t srcStart, int32_t srcLength) -{ return doReplace(length(), 0, srcChars, srcStart, srcLength); } +{ return doAppend(srcChars, srcStart, srcLength); } inline UnicodeString& UnicodeString::append(const UChar *srcChars, int32_t srcLength) -{ return doReplace(length(), 0, srcChars, 0, srcLength); } +{ return doAppend(srcChars, 0, srcLength); } inline UnicodeString& UnicodeString::append(UChar srcChar) -{ return doReplace(length(), 0, &srcChar, 0, 1); } +{ return doAppend(&srcChar, 0, 1); } inline UnicodeString& UnicodeString::operator+= (UChar ch) -{ return doReplace(length(), 0, &ch, 0, 1); } +{ return doAppend(&ch, 0, 1); } inline UnicodeString& UnicodeString::operator+= (UChar32 ch) { @@ -4369,7 +4372,7 @@ inline UnicodeString& UnicodeString::operator+= (const UnicodeString& srcText) -{ return doReplace(length(), 0, srcText, 0, srcText.length()); } +{ return doAppend(srcText, 0, srcText.length()); } inline UnicodeString& UnicodeString::insert(int32_t start, diff -Nura icu/source/common/unistr.cpp icu_new/source/common/unistr.cpp --- icu/source/common/unistr.cpp 2013-10-05 04:49:24.000000000 +0800 +++ icu_new/source/common/unistr.cpp 2020-04-13 17:38:16.052000000 +0800 @@ -216,7 +216,7 @@ : fShortLength(0), fFlags(kShortString) { - doReplace(0, 0, text, 0, -1); + doAppend(text, 0, -1); } UnicodeString::UnicodeString(const UChar *text, @@ -224,7 +224,7 @@ : fShortLength(0), fFlags(kShortString) { - doReplace(0, 0, text, 0, textLength); + doAppend(text, 0, textLength); } UnicodeString::UnicodeString(UBool isTerminated, @@ -1300,8 +1300,8 @@ UBool isError = FALSE; U16_APPEND(buffer, _length, U16_MAX_LENGTH, srcChar, isError); // We test isError so that the compiler does not complain that we don't. - // If isError then _length==0 which turns the doReplace() into a no-op anyway. - return isError ? *this : doReplace(length(), 0, buffer, 0, _length); + // If isError then _length==0 which turns the doAppend() into a no-op anyway. + return isError ? *this : doAppend(buffer, 0, _length); } UnicodeString& @@ -1311,17 +1311,12 @@ int32_t srcStart, int32_t srcLength) { - if(!src.isBogus()) { - // pin the indices to legal values - src.pinIndices(srcStart, srcLength); - - // get the characters from src - // and replace the range in ourselves with them - return doReplace(start, length, src.getArrayStart(), srcStart, srcLength); - } else { - // remove the range - return doReplace(start, length, 0, 0, 0); - } + // pin the indices to legal values + src.pinIndices(srcStart, srcLength); + + // get the characters from src + // and replace the range in ourselves with them + return doReplace(start, length, src.getArrayStart(), srcStart, srcLength); } UnicodeString& @@ -1357,6 +1352,10 @@ } } + if(start == oldLength) { + return doAppend(srcChars, srcStart, srcLength); + } + if(srcChars == 0) { srcStart = srcLength = 0; } else if(srcLength < 0) { @@ -1364,42 +1363,13 @@ srcLength = u_strlen(srcChars + srcStart); } - // calculate the size of the string after the replace - int32_t newLength; - - // optimize append() onto a large-enough, owned string - if(start >= oldLength) { - if(srcLength == 0) { - return *this; - } - newLength = oldLength + srcLength; - if(newLength <= getCapacity() && isBufferWritable()) { - UChar *oldArray = getArrayStart(); - // Do not copy characters when - // UChar *buffer=str.getAppendBuffer(...); - // is followed by - // str.append(buffer, length); - // or - // str.appendString(buffer, length) - // or similar. - if(srcChars + srcStart != oldArray + start || start > oldLength) { - us_arrayCopy(srcChars, srcStart, oldArray, oldLength, srcLength); - } - setLength(newLength); - return *this; - } else { - // pin the indices to legal values - start = oldLength; - length = 0; - } - } else { - // pin the indices to legal values - pinIndices(start, length); + // pin the indices to legal values + pinIndices(start, length); - newLength = oldLength - length + srcLength; - } + // calculate the size of the string after the replace + int32_t newLength = oldLength - length + srcLength; - // the following may change fArray but will not copy the current contents; + // cloneArrayIfNeeded(doCopyArray=FALSE) may change fArray but will not copy the current contents; // therefore we need to keep the current fArray UChar oldStackBuffer[US_STACKBUF_SIZE]; UChar *oldArray; @@ -1450,6 +1420,73 @@ return *this; } +// Versions of doReplace() only for append() variants. +// doReplace() and doAppend() optimize for different cases. + +UnicodeString& +UnicodeString::doAppend(const UnicodeString& src, int32_t srcStart, int32_t srcLength) { + if(srcLength == 0) { + return *this; + } + + // pin the indices to legal values + src.pinIndices(srcStart, srcLength); + return doAppend(src.getArrayStart(), srcStart, srcLength); +} + +UnicodeString& +UnicodeString::doAppend(const UChar *srcChars, int32_t srcStart, int32_t srcLength) { + if(!isWritable() || srcLength == 0 || srcChars == NULL) { + return *this; + } + + if(srcLength < 0) { + // get the srcLength if necessary + if((srcLength = u_strlen(srcChars + srcStart)) == 0) { + return *this; + } + } + + int32_t oldLength = length(); + int32_t newLength; + if (uprv_add32_overflow(oldLength, srcLength, &newLength)) { + setToBogus(); + return *this; + } + + // Check for append onto ourself + const UChar* oldArray = getArrayStart(); + if (isBufferWritable() && + oldArray < srcChars + srcLength && + srcChars < oldArray + oldLength) { + // Copy into a new UnicodeString and start over + UnicodeString copy(srcChars, srcLength); + if (copy.isBogus()) { + setToBogus(); + return *this; + } + return doAppend(copy.getArrayStart(), 0, srcLength); + } + + // optimize append() onto a large-enough, owned string + if((newLength <= getCapacity() && isBufferWritable()) || + cloneArrayIfNeeded(newLength, newLength + (newLength >> 2) + kGrowSize)) { + UChar *newArray = getArrayStart(); + // Do not copy characters when + // UChar *buffer=str.getAppendBuffer(...); + // is followed by + // str.append(buffer, length); + // or + // str.appendString(buffer, length) + // or similar. + if(srcChars + srcStart != newArray + oldLength) { + us_arrayCopy(srcChars, srcStart, newArray, oldLength, srcLength); + } + setLength(newLength); + } + return *this; +} + /** * Replaceable API */ @@ -1746,7 +1783,7 @@ UBool UnicodeStringAppendable::appendCodeUnit(UChar c) { - return str.doReplace(str.length(), 0, &c, 0, 1).isWritable(); + return str.doAppend(&c, 0, 1).isWritable(); } UBool @@ -1755,12 +1792,12 @@ int32_t cLength = 0; UBool isError = FALSE; U16_APPEND(buffer, cLength, U16_MAX_LENGTH, c, isError); - return !isError && str.doReplace(str.length(), 0, buffer, 0, cLength).isWritable(); + return !isError && str.doAppend(buffer, 0, cLength).isWritable(); } UBool UnicodeStringAppendable::appendString(const UChar *s, int32_t length) { - return str.doReplace(str.length(), 0, s, 0, length).isWritable(); + return str.doAppend(s, 0, length).isWritable(); } UBool diff -Nura icu/source/test/intltest/ustrtest.cpp icu_new/source/test/intltest/ustrtest.cpp --- icu/source/test/intltest/ustrtest.cpp 2013-10-05 04:47:58.000000000 +0800 +++ icu_new/source/test/intltest/ustrtest.cpp 2020-04-15 12:17:33.235000000 +0800 @@ -64,6 +64,7 @@ case 21: name = "TestUnicodeStringImplementsAppendable"; if (exec) TestUnicodeStringImplementsAppendable(); break; case 22: name = "TestSizeofUnicodeString"; if (exec) TestSizeofUnicodeString(); break; case 23: name = "TestStartsWithAndEndsWithNulTerminated"; if (exec) TestStartsWithAndEndsWithNulTerminated(); break; + case 24: name = "TestLargeAppend"; if (exec) TestLargeAppend(); break; default: name = ""; break; //needed to end loop } @@ -2117,3 +2118,64 @@ errln("sizeof(UnicodeString)=%d, expected %d", (int)sizeofUniStr, (int)expected); } } + +void UnicodeStringTest::TestLargeAppend() { + if(quick) return; + + IcuTestErrorCode status(*this, "TestLargeAppend"); + // Make a large UnicodeString + int32_t len = 0xAFFFFFF; + UnicodeString str; + UChar *buf = str.getBuffer(len); + // A fast way to set buffer to valid Unicode. + // 4E4E is a valid unicode character + uprv_memset(buf, 0x4e, len * 2); + str.releaseBuffer(len); + UnicodeString dest; + // Append it 16 times + // 0xAFFFFFF times 16 is 0xA4FFFFF1, + // which is greater than INT32_MAX, which is 0x7FFFFFFF. + int64_t total = 0; + for (int32_t i = 0; i < 16; i++) { + dest.append(str); + total += len; + if (total <= INT32_MAX) { + assertFalse("dest is not bogus", dest.isBogus()); + } else { + assertTrue("dest should be bogus", dest.isBogus()); + } + } + dest.remove(); + total = 0; + for (int32_t i = 0; i < 16; i++) { + dest.append(str); + total += len; + if (total + len <= INT32_MAX) { + assertFalse("dest is not bogus", dest.isBogus()); + } else if (total <= INT32_MAX) { + // Check that a string of exactly the maximum size works + UnicodeString str2; + int32_t remain = INT32_MAX - total; + UChar *buf2 = str2.getBuffer(remain); + if (buf2 == nullptr) { + // if somehow memory allocation fail, return the test + return; + } + uprv_memset(buf2, 0x4e, remain * 2); + str2.releaseBuffer(remain); + dest.append(str2); + total += remain; + assertEquals("When a string of exactly the maximum size works", (int64_t)INT32_MAX, total); + assertEquals("When a string of exactly the maximum size works", INT32_MAX, dest.length()); + assertFalse("dest is not bogus", dest.isBogus()); + + // Check that a string size+1 goes bogus + str2.truncate(1); + dest.append(str2); + total++; + assertTrue("dest should be bogus", dest.isBogus()); + } else { + assertTrue("dest should be bogus", dest.isBogus()); + } + } +} diff -Nura icu/source/test/intltest/ustrtest.h icu_new/source/test/intltest/ustrtest.h --- icu/source/test/intltest/ustrtest.h 2013-10-05 04:47:54.000000000 +0800 +++ icu_new/source/test/intltest/ustrtest.h 2020-04-14 23:56:27.312000000 +0800 @@ -88,6 +88,7 @@ void TestAppendable(); void TestUnicodeStringImplementsAppendable(); void TestSizeofUnicodeString(); + void TestLargeAppend(); }; class StringCaseTest: public IntlTest {
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor