Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:15-SP4
icu.25551
icu-CVE-2020-10531.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File icu-CVE-2020-10531.patch of Package icu.25551
diff -Nura icu/source/common/putil.cpp icu_new/source/common/putil.cpp --- icu/source/common/putil.cpp 2017-11-01 03:04:49.000000000 +0800 +++ icu_new/source/common/putil.cpp 2020-03-29 23:03:31.071000000 +0800 @@ -533,6 +533,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 2017-10-12 00:24:35.000000000 +0800 +++ icu_new/source/common/putilimp.h 2020-03-29 23:05:37.853000000 +0800 @@ -391,6 +391,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/unistr.cpp icu_new/source/common/unistr.cpp --- icu/source/common/unistr.cpp 2017-05-26 03:03:13.000000000 +0800 +++ icu_new/source/common/unistr.cpp 2020-03-27 17:58:18.374000000 +0800 @@ -1544,7 +1544,12 @@ } int32_t oldLength = length(); - int32_t newLength = oldLength + srcLength; + int32_t newLength; + if (uprv_add32_overflow(oldLength, srcLength, &newLength)) { + setToBogus(); + return *this; + } + // optimize append() onto a large-enough, owned string if((newLength <= getCapacity() && isBufferWritable()) || cloneArrayIfNeeded(newLength, getGrowCapacity(newLength))) { diff -Nura icu/source/i18n/number_decimalquantity.cpp icu_new/source/i18n/number_decimalquantity.cpp --- icu/source/i18n/number_decimalquantity.cpp 2017-10-26 02:41:15.000000000 +0800 +++ icu_new/source/i18n/number_decimalquantity.cpp 2020-03-30 00:01:12.501000000 +0800 @@ -187,11 +187,14 @@ return scale + precision - 1; } -void DecimalQuantity::adjustMagnitude(int32_t delta) { +bool DecimalQuantity::adjustMagnitude(int32_t delta) { if (precision != 0) { - scale += delta; - origDelta += delta; + // i.e., scale += delta; origDelta += delta + bool overflow = uprv_add32_overflow(scale, delta, &scale); + overflow = uprv_add32_overflow(origDelta, delta, &origDelta) || overflow; + return overflow; } + return false; } StandardPlural::Form DecimalQuantity::getStandardPlural(const PluralRules *rules) const { diff -Nura icu/source/i18n/number_decimalquantity.h icu_new/source/i18n/number_decimalquantity.h --- icu/source/i18n/number_decimalquantity.h 2017-10-12 00:24:33.000000000 +0800 +++ icu_new/source/i18n/number_decimalquantity.h 2020-03-29 23:45:09.313000000 +0800 @@ -101,7 +101,7 @@ * * @param delta The number of magnitudes of ten to change by. */ - void adjustMagnitude(int32_t delta); + bool adjustMagnitude(int32_t delta); /** * @return The power of ten corresponding to the most significant nonzero digit. diff -Nura icu/source/test/cintltst/putiltst.c icu_new/source/test/cintltst/putiltst.c --- icu/source/test/cintltst/putiltst.c 2017-02-01 03:51:24.000000000 +0800 +++ icu_new/source/test/cintltst/putiltst.c 2020-03-29 23:49:57.308000000 +0800 @@ -128,6 +128,20 @@ log_err("ERROR: uprv_isInfinite failed.\n"); } + log_verbose("Testing the APIs uprv_add32_overflow and uprv_mul32_overflow\n"); + int32_t overflow_result; + doAssert(FALSE, uprv_add32_overflow(INT32_MAX - 2, 1, &overflow_result), "should not overflow"); + doAssert(INT32_MAX - 1, overflow_result, "should equal INT32_MAX - 1"); + doAssert(FALSE, uprv_add32_overflow(INT32_MAX - 2, 2, &overflow_result), "should not overflow"); + doAssert(INT32_MAX, overflow_result, "should equal exactly INT32_MAX"); + doAssert(TRUE, uprv_add32_overflow(INT32_MAX - 2, 3, &overflow_result), "should overflow"); + doAssert(FALSE, uprv_mul32_overflow(INT32_MAX / 5, 4, &overflow_result), "should not overflow"); + doAssert(INT32_MAX / 5 * 4, overflow_result, "should equal INT32_MAX / 5 * 4"); + doAssert(TRUE, uprv_mul32_overflow(INT32_MAX / 5, 6, &overflow_result), "should overflow"); + // Test on negative numbers: + doAssert(FALSE, uprv_add32_overflow(-3, -2, &overflow_result), "should not overflow"); + doAssert(-5, overflow_result, "should equal -5"); + #if 0 log_verbose("Testing the API uprv_digitsAfterDecimal()....\n"); doAssert(uprv_digitsAfterDecimal(value1), 3, "uprv_digitsAfterDecimal() failed."); diff -Nura icu/source/test/intltest/ustrtest.cpp icu_new/source/test/intltest/ustrtest.cpp --- icu/source/test/intltest/ustrtest.cpp 2017-10-12 00:24:32.000000000 +0800 +++ icu_new/source/test/intltest/ustrtest.cpp 2020-03-27 18:03:34.407000000 +0800 @@ -64,6 +64,7 @@ TESTCASE_AUTO(TestUInt16Pointers); TESTCASE_AUTO(TestWCharPointers); TESTCASE_AUTO(TestNullPointers); + TESTCASE_AUTO(TestLargeAppend); TESTCASE_AUTO_END; } @@ -2248,3 +2249,65 @@ UnicodeString(u"def").extract(nullptr, 0, errorCode); assertEquals("buffer overflow extracting to nullptr", U_BUFFER_OVERFLOW_ERROR, errorCode); } + + +void UnicodeStringTest::TestLargeAppend() { + if(quick) return; + + IcuTestErrorCode status(*this, "TestLargeAppend"); + // Make a large UnicodeString + int32_t len = 0xAFFFFFF; + UnicodeString str; + char16_t *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; + char16_t *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 2017-03-15 05:02:21.000000000 +0800 +++ icu_new/source/test/intltest/ustrtest.h 2020-03-27 18:04:05.779000000 +0800 @@ -96,6 +96,7 @@ void TestUInt16Pointers(); void TestWCharPointers(); void TestNullPointers(); + void TestLargeAppend(); }; #endif
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