CVE-2018-18928 (published 2018-11-04T20:29Z)

International Components for Unicode (ICU) for C/C++ 63.1 has an integer overflow in number::impl::DecimalQuantity::toScientificString() in i18n/number_decimalquantity.cpp.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-190
cwe_name: Integer Overflow or Wraparound
description: The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
extended_description: 
            
            
            
            
         
         

Fix information:
repo_url: https://github.com/unicode-org/icu
commit_details: repo_url: https://github.com/unicode-org/icu
author: Shane Carr
author_date: 2018-10-29 23:52:44-07:00
msg: ICU-20246 Fixing another integer overflow in number parsing.
repository: repo_url: https://github.com/unicode-org/icu
repo_name: unicode-org/icu
description: The home of the ICU project source code.
repo_language: C++
owner: unicode-org
file_changes: filename: fmtable.cpp
change_type: ModificationType.MODIFY
diff: @@ -734,7 +734,7 @@ CharString *Formattable::internalGetCharString(UErrorCode &status) {
       // not print scientific notation for magnitudes greater than -5 and smaller than some amount (+5?).
       if (fDecimalQuantity->isZero()) {
         fDecimalStr->append("0", -1, status);
-      } else if (std::abs(fDecimalQuantity->getMagnitude()) < 5) {
+      } else if (fDecimalQuantity->getMagnitude() != INT32_MIN && std::abs(fDecimalQuantity->getMagnitude()) < 5) {
         fDecimalStr->appendInvariantChars(fDecimalQuantity->toPlainString(), status);
       } else {
         fDecimalStr->appendInvariantChars(fDecimalQuantity->toScientificString(), status);

programming_language: C++
filename: number_decimalquantity.cpp
change_type: ModificationType.MODIFY
diff: @@ -898,7 +898,10 @@ UnicodeString DecimalQuantity::toScientificString() const {
     }
     result.append(u'E');
     int32_t _scale = upperPos + scale;
-    if (_scale < 0) {
+    if (_scale == INT32_MIN) {
+        result.append({u"-2147483648", -1});
+        return result;
+    } else if (_scale < 0) {
         _scale *= -1;
         result.append(u'-');
     } else {

programming_language: C++
filename: numfmtst.cpp
change_type: ModificationType.MODIFY
diff: @@ -9226,6 +9226,14 @@ void NumberFormatTest::Test20037_ScientificIntegerOverflow() {
     assertEquals(u"Should not overflow and should parse only the first exponent",
                  u"1E-2147483647",
                  {sp.data(), sp.length(), US_INV});
+
+    // Test edge case overflow of exponent
+    result = Formattable();
+    nf->parse(u".0003e-2147483644", result, status);
+    sp = result.getDecimalNumber(status);
+    assertEquals(u"Should not overflow",
+                 u"3E-2147483648",
+                 {sp.data(), sp.length(), US_INV});
 }
 
 void NumberFormatTest::Test13840_ParseLongStringCrash() {

programming_language: Shell
filename: DecimalQuantity_AbstractBCD.java
change_type: ModificationType.MODIFY
diff: @@ -1067,7 +1067,10 @@ public void toScientificString(StringBuilder result) {
         }
         result.append('E');
         int _scale = upperPos + scale;
-        if (_scale < 0) {
+        if (_scale == Integer.MIN_VALUE) {
+            result.append("-2147483648");
+            return;
+        } else if (_scale < 0) {
             _scale *= -1;
             result.append('-');
         } else {

programming_language: Java
filename: DecimalQuantity_DualStorageBCD.java
change_type: ModificationType.MODIFY
diff: @@ -239,7 +239,15 @@ protected BigDecimal bcdToBigDecimal() {
                 tempLong = tempLong * 10 + getDigitPos(shift);
             }
             BigDecimal result = BigDecimal.valueOf(tempLong);
-            result = result.scaleByPowerOfTen(scale);
+            try {
+                result = result.scaleByPowerOfTen(scale);
+            } catch (ArithmeticException e) {
+                if (e.getMessage().contains("Underflow")) {
+                    result = BigDecimal.ZERO;
+                } else {
+                    throw e;
+                }
+            }
             if (isNegative())
                 result = result.negate();
             return result;

programming_language: Java
filename: NumberFormatTest.java
change_type: ModificationType.MODIFY
diff: @@ -6325,6 +6325,11 @@ public void Test20037_ScientificIntegerOverflow() throws ParseException {
         result = nf.parse("1E-547483647");
         assertEquals("Should *not* snap to zero",
                 "1E-547483647", result.toString());
+
+        // Test edge case overflow of exponent
+        result = nf.parse(".0003e-2147483644");
+        assertEquals("Should not overflow",
+                "0", result.toString());
     }
 
     @Test

programming_language: Java