diff --git a/README.chromium b/README.chromium index f2ff451..1301d73 100644 --- a/README.chromium +++ b/README.chromium
@@ -288,3 +288,10 @@ - https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=68895 - https://issues.chromium.org/u/1/issues/345352978 - https://unicode-org.atlassian.net/browse/ICU-22730 + +17. Patch UnicodeString to fix heap-buffer-overflow . + patches/unicode_string.patch + - https://unicode-org.atlassian.net/browse/ICU-23060 + - https://g-issues.chromium.org/issues/393989622 + - https://patch-diff.githubusercontent.com/raw/unicode-org/icu/pull/3416.diff + - https://patch-diff.githubusercontent.com/raw/unicode-org/icu/pull/3420.diff
diff --git a/patches/unicode_string.patch b/patches/unicode_string.patch new file mode 100644 index 0000000..12d9cdb --- /dev/null +++ b/patches/unicode_string.patch
@@ -0,0 +1,105 @@ +diff --git a/source/common/unistr.cpp b/source/common/unistr.cpp +index 04f01cfa..626f8886 100644 +--- a/source/common/unistr.cpp ++++ b/source/common/unistr.cpp +@@ -1865,6 +1865,13 @@ UnicodeString::cloneArrayIfNeeded(int32_t newCapacity, + growCapacity = newCapacity; + } else if(newCapacity <= US_STACKBUF_SIZE && growCapacity > US_STACKBUF_SIZE) { + growCapacity = US_STACKBUF_SIZE; ++ } else if(newCapacity > growCapacity) { ++ setToBogus(); ++ return false; // bad inputs ++ } ++ if(growCapacity > kMaxCapacity) { ++ setToBogus(); ++ return false; + } + + // save old values +diff --git a/source/test/intltest/ustrtest.cpp b/source/test/intltest/ustrtest.cpp +index 26c51b9c..71ebde4b 100644 +--- a/source/test/intltest/ustrtest.cpp ++++ b/source/test/intltest/ustrtest.cpp +@@ -68,6 +68,7 @@ void UnicodeStringTest::runIndexedTest( int32_t index, UBool exec, const char* & + TESTCASE_AUTO(TestNullPointers); + TESTCASE_AUTO(TestUnicodeStringInsertAppendToSelf); + TESTCASE_AUTO(TestLargeAppend); ++ TESTCASE_AUTO(TestLargeMemory); + TESTCASE_AUTO_END; + } + +@@ -2328,6 +2329,18 @@ void UnicodeStringTest::TestUnicodeStringInsertAppendToSelf() { + assertEquals("", u"abbcdcde", str); + } + ++void UnicodeStringTest::TestLargeMemory() { ++#if U_PLATFORM_IS_LINUX_BASED || U_PLATFORM_IS_DARWIN_BASED ++ if(quick) { return; } ++ IcuTestErrorCode status(*this, "TestLargeMemory"); ++ constexpr uint32_t len = 2147483643; ++ char16_t *buf = new char16_t[len]; ++ if (buf == nullptr) { return; } ++ uprv_memset(buf, 0x4e, len * 2); ++ icu::UnicodeString test(buf, len); ++ delete [] buf; ++#endif ++} + void UnicodeStringTest::TestLargeAppend() { + if(quick) return; + +@@ -2356,15 +2369,17 @@ void UnicodeStringTest::TestLargeAppend() { + } + dest.remove(); + total = 0; ++ // Copy kMaxCapacity from common/unistr.cpp ++ const int32_t kMaxCapacity = 0x7ffffff5; + for (int32_t i = 0; i < 16; i++) { + dest.append(str); + total += len; +- if (total + len <= INT32_MAX) { ++ if (total + len <= kMaxCapacity) { + assertFalse("dest is not bogus", dest.isBogus()); +- } else if (total <= INT32_MAX) { ++ } else if (total <= kMaxCapacity) { + // Check that a string of exactly the maximum size works + UnicodeString str2; +- int32_t remain = static_cast<int32_t>(INT32_MAX - total); ++ int32_t remain = static_cast<int32_t>(kMaxCapacity - total); + char16_t *buf2 = str2.getBuffer(remain); + if (buf2 == nullptr) { + // if somehow memory allocation fail, return the test +@@ -2374,14 +2389,19 @@ void UnicodeStringTest::TestLargeAppend() { + 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()); ++ assertEquals("When a string of exactly the maximum size works", static_cast<int64_t>(kMaxCapacity), total); ++ assertEquals("When a string of exactly the maximum size works", kMaxCapacity, dest.length()); + assertFalse("dest is not bogus", dest.isBogus()); + +- // Check that a string size+1 goes bogus ++ // Check that a string size+1 does not go bogus (one more byte reserved for NUL) + str2.truncate(1); + dest.append(str2); + total++; ++ assertFalse("dest should be not bogus", dest.isBogus()); ++ // Check that a string size+2 goes bogus (beyond the byte reserved ++ // for NUL) ++ dest.append(str2); ++ total++; + assertTrue("dest should be bogus", dest.isBogus()); + } else { + assertTrue("dest should be bogus", dest.isBogus()); +diff --git a/source/test/intltest/ustrtest.h b/source/test/intltest/ustrtest.h +index 088b7139..9e50d365 100644 +--- a/source/test/intltest/ustrtest.h ++++ b/source/test/intltest/ustrtest.h +@@ -92,6 +92,7 @@ public: + void TestUnicodeStringImplementsAppendable(); + void TestSizeofUnicodeString(); + void TestMoveSwap(); ++ void TestLargeMemory(); + + void TestUInt16Pointers(); + void TestWCharPointers();
diff --git a/source/common/unistr.cpp b/source/common/unistr.cpp index 04f01cf..626f888 100644 --- a/source/common/unistr.cpp +++ b/source/common/unistr.cpp
@@ -1865,6 +1865,13 @@ growCapacity = newCapacity; } else if(newCapacity <= US_STACKBUF_SIZE && growCapacity > US_STACKBUF_SIZE) { growCapacity = US_STACKBUF_SIZE; + } else if(newCapacity > growCapacity) { + setToBogus(); + return false; // bad inputs + } + if(growCapacity > kMaxCapacity) { + setToBogus(); + return false; } // save old values
diff --git a/source/test/intltest/ustrtest.cpp b/source/test/intltest/ustrtest.cpp index 26c51b9..71ebde4 100644 --- a/source/test/intltest/ustrtest.cpp +++ b/source/test/intltest/ustrtest.cpp
@@ -68,6 +68,7 @@ TESTCASE_AUTO(TestNullPointers); TESTCASE_AUTO(TestUnicodeStringInsertAppendToSelf); TESTCASE_AUTO(TestLargeAppend); + TESTCASE_AUTO(TestLargeMemory); TESTCASE_AUTO_END; } @@ -2328,6 +2329,18 @@ assertEquals("", u"abbcdcde", str); } +void UnicodeStringTest::TestLargeMemory() { +#if U_PLATFORM_IS_LINUX_BASED || U_PLATFORM_IS_DARWIN_BASED + if(quick) { return; } + IcuTestErrorCode status(*this, "TestLargeMemory"); + constexpr uint32_t len = 2147483643; + char16_t *buf = new char16_t[len]; + if (buf == nullptr) { return; } + uprv_memset(buf, 0x4e, len * 2); + icu::UnicodeString test(buf, len); + delete [] buf; +#endif +} void UnicodeStringTest::TestLargeAppend() { if(quick) return; @@ -2356,15 +2369,17 @@ } dest.remove(); total = 0; + // Copy kMaxCapacity from common/unistr.cpp + const int32_t kMaxCapacity = 0x7ffffff5; for (int32_t i = 0; i < 16; i++) { dest.append(str); total += len; - if (total + len <= INT32_MAX) { + if (total + len <= kMaxCapacity) { assertFalse("dest is not bogus", dest.isBogus()); - } else if (total <= INT32_MAX) { + } else if (total <= kMaxCapacity) { // Check that a string of exactly the maximum size works UnicodeString str2; - int32_t remain = static_cast<int32_t>(INT32_MAX - total); + int32_t remain = static_cast<int32_t>(kMaxCapacity - total); char16_t *buf2 = str2.getBuffer(remain); if (buf2 == nullptr) { // if somehow memory allocation fail, return the test @@ -2374,14 +2389,19 @@ 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()); + assertEquals("When a string of exactly the maximum size works", static_cast<int64_t>(kMaxCapacity), total); + assertEquals("When a string of exactly the maximum size works", kMaxCapacity, dest.length()); assertFalse("dest is not bogus", dest.isBogus()); - // Check that a string size+1 goes bogus + // Check that a string size+1 does not go bogus (one more byte reserved for NUL) str2.truncate(1); dest.append(str2); total++; + assertFalse("dest should be not bogus", dest.isBogus()); + // Check that a string size+2 goes bogus (beyond the byte reserved + // for NUL) + dest.append(str2); + total++; assertTrue("dest should be bogus", dest.isBogus()); } else { assertTrue("dest should be bogus", dest.isBogus());
diff --git a/source/test/intltest/ustrtest.h b/source/test/intltest/ustrtest.h index 088b713..9e50d36 100644 --- a/source/test/intltest/ustrtest.h +++ b/source/test/intltest/ustrtest.h
@@ -92,6 +92,7 @@ void TestUnicodeStringImplementsAppendable(); void TestSizeofUnicodeString(); void TestMoveSwap(); + void TestLargeMemory(); void TestUInt16Pointers(); void TestWCharPointers();