CVE-2020-10531.patch 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. Backport of <https://github.com/unicode-org/icu/commit/b7d08bc04>
  2. ~~~
  3. From b7d08bc04a4296982fcef8b6b8a354a9e4e7afca Mon Sep 17 00:00:00 2001
  4. From: Frank Tang <ftang@chromium.org>
  5. Date: Sat, 1 Feb 2020 02:39:04 +0000
  6. Subject: [PATCH] ICU-20958 Prevent SEGV_MAPERR in append
  7. See #971
  8. X-SVN-Rev: 39671
  9. ---
  10. icu4c/source/common/utext.cpp | 27 +++++++++--
  11. icu4c/source/test/intltest/utxttest.cpp | 62 +++++++++++++++++++++++++
  12. icu4c/source/test/intltest/utxttest.h | 1 +
  13. 3 files changed, 85 insertions(+), 5 deletions(-)
  14. ~~~
  15. Includes code from Debian `ICU-13634.patch`:
  16. https://sources.debian.org/patches/icu/57.1-6+deb9u4/ICU-13634.patch/
  17. --- source/common/putil.cpp
  18. +++ source/common/putil.cpp
  19. @@ -516,6 +516,17 @@ uprv_fmin(double x, double y)
  20. return (x > y ? y : x);
  21. }
  22. +U_CAPI UBool U_EXPORT2
  23. +uprv_add32_overflow(int32_t a, int32_t b, int32_t* res) {
  24. + // NOTE: Some compilers (GCC, Clang) have primitives available, like __builtin_add_overflow.
  25. + // This function could be optimized by calling one of those primitives.
  26. + auto a64 = static_cast<int64_t>(a);
  27. + auto b64 = static_cast<int64_t>(b);
  28. + int64_t res64 = a64 + b64;
  29. + *res = static_cast<int32_t>(res64);
  30. + return res64 != *res;
  31. +}
  32. +
  33. /**
  34. * Truncates the given double.
  35. * trunc(3.3) = 3.0, trunc (-3.3) = -3.0
  36. --- source/common/putilimp.h
  37. +++ source/common/putilimp.h
  38. @@ -394,6 +394,19 @@ U_INTERNAL double U_EXPORT2 uprv_log(double d);
  39. */
  40. U_INTERNAL double U_EXPORT2 uprv_round(double x);
  41. +/**
  42. + * Adds the signed integers a and b, storing the result in res.
  43. + * Checks for signed integer overflow.
  44. + * Similar to the GCC/Clang extension __builtin_add_overflow
  45. + *
  46. + * @param a The first operand.
  47. + * @param b The second operand.
  48. + * @param res a + b
  49. + * @return true if overflow occurred; false if no overflow occurred.
  50. + * @internal
  51. + */
  52. +U_INTERNAL UBool U_EXPORT2 uprv_add32_overflow(int32_t a, int32_t b, int32_t* res);
  53. +
  54. #if 0
  55. /**
  56. * Returns the number of digits after the decimal point in a double number x.
  57. --- source/common/unistr.cpp
  58. +++ source/common/unistr.cpp
  59. @@ -1543,7 +1543,11 @@ UnicodeString::doAppend(const UChar *srcChars, int32_t srcStart, int32_t srcLeng
  60. }
  61. int32_t oldLength = length();
  62. - int32_t newLength = oldLength + srcLength;
  63. + int32_t newLength;
  64. + if (uprv_add32_overflow(oldLength, srcLength, &newLength)) {
  65. + setToBogus();
  66. + return *this;
  67. + }
  68. // optimize append() onto a large-enough, owned string
  69. if((newLength <= getCapacity() && isBufferWritable()) ||
  70. cloneArrayIfNeeded(newLength, getGrowCapacity(newLength))) {
  71. --- source/test/cintltst/putiltst.c
  72. +++ source/test/cintltst/putiltst.c
  73. @@ -128,6 +128,17 @@ static void TestPUtilAPI(void){
  74. log_err("ERROR: uprv_isInfinite failed.\n");
  75. }
  76. + log_verbose("Testing the APIs uprv_add32_overflow\n");
  77. + int32_t overflow_result;
  78. + doAssert(FALSE, uprv_add32_overflow(INT32_MAX - 2, 1, &overflow_result), "should not overflow");
  79. + doAssert(INT32_MAX - 1, overflow_result, "should equal INT32_MAX - 1");
  80. + doAssert(FALSE, uprv_add32_overflow(INT32_MAX - 2, 2, &overflow_result), "should not overflow");
  81. + doAssert(INT32_MAX, overflow_result, "should equal exactly INT32_MAX");
  82. + doAssert(TRUE, uprv_add32_overflow(INT32_MAX - 2, 3, &overflow_result), "should overflow");
  83. + // Test on negative numbers:
  84. + doAssert(FALSE, uprv_add32_overflow(-3, -2, &overflow_result), "should not overflow");
  85. + doAssert(-5, overflow_result, "should equal -5");
  86. +
  87. #if 0
  88. log_verbose("Testing the API uprv_digitsAfterDecimal()....\n");
  89. doAssert(uprv_digitsAfterDecimal(value1), 3, "uprv_digitsAfterDecimal() failed.");
  90. --- source/test/intltest/ustrtest.cpp
  91. +++ source/test/intltest/ustrtest.cpp
  92. @@ -58,6 +58,7 @@ void UnicodeStringTest::runIndexedTest( int32_t index, UBool exec, const char* &
  93. TESTCASE_AUTO(TestSizeofUnicodeString);
  94. TESTCASE_AUTO(TestStartsWithAndEndsWithNulTerminated);
  95. TESTCASE_AUTO(TestMoveSwap);
  96. + TESTCASE_AUTO(TestLargeAppend);
  97. TESTCASE_AUTO_END;
  98. }
  99. @@ -2187,3 +2188,64 @@ UnicodeStringTest::TestMoveSwap() {
  100. errln("UnicodeString copy after self-move did not work");
  101. }
  102. }
  103. +
  104. +void UnicodeStringTest::TestLargeAppend() {
  105. + if(quick) return;
  106. +
  107. + IcuTestErrorCode status(*this, "TestLargeAppend");
  108. + // Make a large UnicodeString
  109. + int32_t len = 0xAFFFFFF;
  110. + UnicodeString str;
  111. + char16_t *buf = str.getBuffer(len);
  112. + // A fast way to set buffer to valid Unicode.
  113. + // 4E4E is a valid unicode character
  114. + uprv_memset(buf, 0x4e, len * 2);
  115. + str.releaseBuffer(len);
  116. + UnicodeString dest;
  117. + // Append it 16 times
  118. + // 0xAFFFFFF times 16 is 0xA4FFFFF1,
  119. + // which is greater than INT32_MAX, which is 0x7FFFFFFF.
  120. + int64_t total = 0;
  121. + for (int32_t i = 0; i < 16; i++) {
  122. + dest.append(str);
  123. + total += len;
  124. + if (total <= INT32_MAX) {
  125. + assertFalse("dest is not bogus", dest.isBogus());
  126. + } else {
  127. + assertTrue("dest should be bogus", dest.isBogus());
  128. + }
  129. + }
  130. + dest.remove();
  131. + total = 0;
  132. + for (int32_t i = 0; i < 16; i++) {
  133. + dest.append(str);
  134. + total += len;
  135. + if (total + len <= INT32_MAX) {
  136. + assertFalse("dest is not bogus", dest.isBogus());
  137. + } else if (total <= INT32_MAX) {
  138. + // Check that a string of exactly the maximum size works
  139. + UnicodeString str2;
  140. + int32_t remain = INT32_MAX - total;
  141. + char16_t *buf2 = str2.getBuffer(remain);
  142. + if (buf2 == nullptr) {
  143. + // if somehow memory allocation fail, return the test
  144. + return;
  145. + }
  146. + uprv_memset(buf2, 0x4e, remain * 2);
  147. + str2.releaseBuffer(remain);
  148. + dest.append(str2);
  149. + total += remain;
  150. + assertEquals("When a string of exactly the maximum size works", (int64_t)INT32_MAX, total);
  151. + assertEquals("When a string of exactly the maximum size works", INT32_MAX, dest.length());
  152. + assertFalse("dest is not bogus", dest.isBogus());
  153. +
  154. + // Check that a string size+1 goes bogus
  155. + str2.truncate(1);
  156. + dest.append(str2);
  157. + total++;
  158. + assertTrue("dest should be bogus", dest.isBogus());
  159. + } else {
  160. + assertTrue("dest should be bogus", dest.isBogus());
  161. + }
  162. + }
  163. +}
  164. --- source/test/intltest/ustrtest.h
  165. +++ source/test/intltest/ustrtest.h
  166. @@ -92,6 +92,7 @@ public:
  167. void TestUnicodeStringImplementsAppendable();
  168. void TestSizeofUnicodeString();
  169. void TestMoveSwap();
  170. + void TestLargeAppend();
  171. };
  172. class StringCaseTest: public IntlTest {