diff options
author | Frank Tang <ftang@chromium.org> | 2022-04-29 16:50:59 -0700 |
---|---|---|
committer | Michael BrĂ¼ning <michael.bruning@qt.io> | 2022-05-20 13:06:16 +0000 |
commit | 0d154ed1e4b696678784ce6ba0c2d80507e59eb7 (patch) | |
tree | 7ab9be1c756073c382e77e8fa10ca8ac256b97c1 | |
parent | d1d05e7291a42363f63e979068eb6aa13d4d19a2 (diff) | |
download | qtwebengine-chromium-0d154ed1e4b696678784ce6ba0c2d80507e59eb7.tar.gz |
[Backport] CVE-2022-1638: Heap buffer overflow in V8 Internationalization
Manual cherry-pick of patch originally reviewed on
https://chromium-review.googlesource.com/c/chromium/deps/icu/+/3614280:
CP PR 2070 fix int32 overflow
https://github.com/unicode-org/icu/pull/2070
https://unicode-org.atlassian.net/browse/ICU-22005
Bug: chromium:1316946
Change-Id: I6cd7d687a55b6cc157b1afa52365908be2992fa6
Reviewed-by: Jungshik Shin <jshin@chromium.org>
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r-- | chromium/third_party/icu/source/i18n/formatted_string_builder.cpp | 55 |
1 files changed, 38 insertions, 17 deletions
diff --git a/chromium/third_party/icu/source/i18n/formatted_string_builder.cpp b/chromium/third_party/icu/source/i18n/formatted_string_builder.cpp index b370f14f2ac..628fbea8711 100644 --- a/chromium/third_party/icu/source/i18n/formatted_string_builder.cpp +++ b/chromium/third_party/icu/source/i18n/formatted_string_builder.cpp @@ -6,6 +6,7 @@ #if !UCONFIG_NO_FORMATTING #include "formatted_string_builder.h" +#include "putilimp.h" #include "unicode/ustring.h" #include "unicode/utf16.h" #include "unicode/unum.h" // for UNumberFormatFields literals @@ -197,6 +198,9 @@ FormattedStringBuilder::splice(int32_t startThis, int32_t endThis, const Unicod int32_t thisLength = endThis - startThis; int32_t otherLength = endOther - startOther; int32_t count = otherLength - thisLength; + if (U_FAILURE(status)) { + return count; + } int32_t position; if (count > 0) { // Overall, chars need to be added. @@ -221,6 +225,9 @@ int32_t FormattedStringBuilder::append(const FormattedStringBuilder &other, UErr int32_t FormattedStringBuilder::insert(int32_t index, const FormattedStringBuilder &other, UErrorCode &status) { + if (U_FAILURE(status)) { + return 0; + } if (this == &other) { status = U_ILLEGAL_ARGUMENT_ERROR; return 0; @@ -255,12 +262,18 @@ int32_t FormattedStringBuilder::prepareForInsert(int32_t index, int32_t count, U U_ASSERT(index >= 0); U_ASSERT(index <= fLength); U_ASSERT(count >= 0); + U_ASSERT(fZero >= 0); + U_ASSERT(fLength >= 0); + U_ASSERT(getCapacity() - fZero >= fLength); + if (U_FAILURE(status)) { + return count; + } if (index == 0 && fZero - count >= 0) { // Append to start fZero -= count; fLength += count; return fZero; - } else if (index == fLength && fZero + fLength + count < getCapacity()) { + } else if (index == fLength && count <= getCapacity() - fZero - fLength) { // Append to end fLength += count; return fZero + fLength - count; @@ -275,18 +288,26 @@ int32_t FormattedStringBuilder::prepareForInsertHelper(int32_t index, int32_t co int32_t oldZero = fZero; char16_t *oldChars = getCharPtr(); Field *oldFields = getFieldPtr(); - if (fLength + count > oldCapacity) { - if ((fLength + count) > INT32_MAX / 2) { - // If we continue, then newCapacity will overlow int32_t in the next line. + int32_t newLength; + if (uprv_add32_overflow(fLength, count, &newLength)) { + status = U_INPUT_TOO_LONG_ERROR; + return -1; + } + int32_t newZero; + if (newLength > oldCapacity) { + if (newLength > INT32_MAX / 2) { + // We do not support more than 1G char16_t in this code because + // dealing with >2G *bytes* can cause subtle bugs. status = U_INPUT_TOO_LONG_ERROR; return -1; } - int32_t newCapacity = (fLength + count) * 2; - int32_t newZero = newCapacity / 2 - (fLength + count) / 2; + // Keep newCapacity also to at most 1G char16_t. + int32_t newCapacity = newLength * 2; + newZero = (newCapacity - newLength) / 2; // C++ note: malloc appears in two places: here and in the assignment operator. - auto newChars = static_cast<char16_t *> (uprv_malloc(sizeof(char16_t) * newCapacity)); - auto newFields = static_cast<Field *>(uprv_malloc(sizeof(Field) * newCapacity)); + auto newChars = static_cast<char16_t *> (uprv_malloc(sizeof(char16_t) * static_cast<size_t>(newCapacity))); + auto newFields = static_cast<Field *>(uprv_malloc(sizeof(Field) * static_cast<size_t>(newCapacity))); if (newChars == nullptr || newFields == nullptr) { uprv_free(newChars); uprv_free(newFields); @@ -315,10 +336,8 @@ int32_t FormattedStringBuilder::prepareForInsertHelper(int32_t index, int32_t co fChars.heap.capacity = newCapacity; fFields.heap.ptr = newFields; fFields.heap.capacity = newCapacity; - fZero = newZero; - fLength += count; } else { - int32_t newZero = oldCapacity / 2 - (fLength + count) / 2; + newZero = (oldCapacity - newLength) / 2; // C++ note: memmove is required because src and dest may overlap. // First copy the entire string to the location of the prefix, and then move the suffix @@ -331,18 +350,20 @@ int32_t FormattedStringBuilder::prepareForInsertHelper(int32_t index, int32_t co uprv_memmove2(oldFields + newZero + index + count, oldFields + newZero + index, sizeof(Field) * (fLength - index)); - - fZero = newZero; - fLength += count; } - U_ASSERT((fZero + index) >= 0); + fZero = newZero; + fLength = newLength; return fZero + index; } int32_t FormattedStringBuilder::remove(int32_t index, int32_t count) { - // TODO: Reset the heap here? (If the string after removal can fit on stack?) + U_ASSERT(0 <= index); + U_ASSERT(index <= fLength); + U_ASSERT(count <= (fLength - index)); + U_ASSERT(index <= getCapacity() - fZero); + int32_t position = index + fZero; - U_ASSERT(position >= 0); + // TODO: Reset the heap here? (If the string after removal can fit on stack?) uprv_memmove2(getCharPtr() + position, getCharPtr() + position + count, sizeof(char16_t) * (fLength - index - count)); |