diff --git a/CVE-2016-6293.patch b/CVE-2016-6293.patch new file mode 100644 index 0000000..dce3be6 --- /dev/null +++ b/CVE-2016-6293.patch @@ -0,0 +1,232 @@ +Index: /source/common/uloc.cpp +=================================================================== +--- /source/common/uloc.cpp (revision 39108) ++++ /source/common/uloc.cpp (revision 39109) +@@ -2247,5 +2247,5 @@ + float q; + int32_t dummy; /* to avoid uninitialized memory copy from qsort */ +- char *locale; ++ char locale[ULOC_FULLNAME_CAPACITY+1]; + } _acceptLangItem; + +@@ -2289,7 +2289,5 @@ + UErrorCode *status) + { +- _acceptLangItem *j; +- _acceptLangItem smallBuffer[30]; +- char **strs; ++ MaybeStackArray<_acceptLangItem, 4> items; // Struct for collecting items. + char tmp[ULOC_FULLNAME_CAPACITY +1]; + int32_t n = 0; +@@ -2301,9 +2299,5 @@ + int32_t i; + int32_t l = (int32_t)uprv_strlen(httpAcceptLanguage); +- int32_t jSize; +- char *tempstr; /* Use for null pointer check */ +- +- j = smallBuffer; +- jSize = UPRV_LENGTHOF(smallBuffer); ++ + if(U_FAILURE(*status)) { + return -1; +@@ -2333,25 +2327,27 @@ + t++; + } +- j[n].q = (float)_uloc_strtod(t,NULL); ++ items[n].q = (float)_uloc_strtod(t,NULL); + } else { + /* no semicolon - it's 1.0 */ +- j[n].q = 1.0f; ++ items[n].q = 1.0f; + paramEnd = itemEnd; + } +- j[n].dummy=0; ++ items[n].dummy=0; + /* eat spaces prior to semi */ + for(t=(paramEnd-1);(paramEnd>s)&&isspace(*t);t--) + ; +- /* Check for null pointer from uprv_strndup */ +- tempstr = uprv_strndup(s,(int32_t)((t+1)-s)); +- if (tempstr == NULL) { +- *status = U_MEMORY_ALLOCATION_ERROR; +- return -1; +- } +- j[n].locale = tempstr; +- uloc_canonicalize(j[n].locale,tmp,UPRV_LENGTHOF(tmp),status); +- if(strcmp(j[n].locale,tmp)) { +- uprv_free(j[n].locale); +- j[n].locale=uprv_strdup(tmp); ++ int32_t slen = ((t+1)-s); ++ if(slen > ULOC_FULLNAME_CAPACITY) { ++ *status = U_BUFFER_OVERFLOW_ERROR; ++ return -1; // too big ++ } ++ uprv_strncpy(items[n].locale, s, slen); ++ items[n].locale[slen]=0; // terminate ++ int32_t clen = uloc_canonicalize(items[n].locale, tmp, UPRV_LENGTHOF(tmp)-1, status); ++ if(U_FAILURE(*status)) return -1; ++ if((clen!=slen) || (uprv_strncmp(items[n].locale, tmp, slen))) { ++ // canonicalization had an effect- copy back ++ uprv_strncpy(items[n].locale, tmp, clen); ++ items[n].locale[clen] = 0; // terminate + } + #if defined(ULOC_DEBUG) +@@ -2363,42 +2359,18 @@ + s++; + } +- if(n>=jSize) { +- if(j==smallBuffer) { /* overflowed the small buffer. */ +- j = static_cast<_acceptLangItem *>(uprv_malloc(sizeof(j[0])*(jSize*2))); +- if(j!=NULL) { +- uprv_memcpy(j,smallBuffer,sizeof(j[0])*jSize); +- } ++ if(n>=items.getCapacity()) { // If we need more items ++ if(NULL == items.resize(items.getCapacity()*2, items.getCapacity())) { ++ *status = U_MEMORY_ALLOCATION_ERROR; ++ return -1; ++ } + #if defined(ULOC_DEBUG) +- fprintf(stderr,"malloced at size %d\n", jSize); ++ fprintf(stderr,"malloced at size %d\n", items.getCapacity()); + #endif +- } else { +- j = static_cast<_acceptLangItem *>(uprv_realloc(j, sizeof(j[0])*jSize*2)); +-#if defined(ULOC_DEBUG) +- fprintf(stderr,"re-alloced at size %d\n", jSize); +-#endif +- } +- jSize *= 2; +- if(j==NULL) { +- *status = U_MEMORY_ALLOCATION_ERROR; +- return -1; +- } +- } +- } +- uprv_sortArray(j, n, sizeof(j[0]), uloc_acceptLanguageCompare, NULL, TRUE, status); ++ } ++ } ++ uprv_sortArray(items.getAlias(), n, sizeof(items[0]), uloc_acceptLanguageCompare, NULL, TRUE, status); ++ LocalArray strs(new const char*[n], *status); + if(U_FAILURE(*status)) { +- if(j != smallBuffer) { +-#if defined(ULOC_DEBUG) +- fprintf(stderr,"freeing j %p\n", j); +-#endif +- uprv_free(j); +- } +- return -1; +- } +- strs = static_cast(uprv_malloc((size_t)(sizeof(strs[0])*n))); +- /* Check for null pointer */ +- if (strs == NULL) { +- uprv_free(j); /* Free to avoid memory leak */ +- *status = U_MEMORY_ALLOCATION_ERROR; +- return -1; ++ return -1; + } + for(i=0;i q <%g>\n", i, j[i].locale, j[i].q);*/ + #endif +- strs[i]=j[i].locale; ++ strs[i]=items[i].locale; + } + res = uloc_acceptLanguage(result, resultAvailable, outResult, +- (const char**)strs, n, availableLocales, status); +- for(i=0;i0)&&uprv_strcmp(tmp, tests[i].expect)) { +- log_err_status(status, "FAIL: #%d: expected %s but got %s\n", i, tests[i].expect, tmp); +- log_info("test #%d: http[%s], ICU[%s], expect %s, %s\n", +- i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect, acceptResult(tests[i].res)); ++ } ++ if((outResult>0)&&uprv_strcmp(tmp, tests[i].expect)) { ++ log_err_status(status, "FAIL: #%d: expected %s but got %s\n", i, tests[i].expect, tmp); ++ log_info("test #%d: http[%s], ICU[%s], expect %s, %s\n", ++ i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect, acceptResult(tests[i].res)); ++ } + } + } diff --git a/CVE-2016-7415.patch b/CVE-2016-7415.patch new file mode 100644 index 0000000..b5c6742 --- /dev/null +++ b/CVE-2016-7415.patch @@ -0,0 +1,176 @@ +Index: source/common/locid.cpp +=================================================================== +--- a/source/common/locid.cpp (revision 39353) ++++ b/source/common/locid.cpp (revision 39356) +@@ -43,4 +43,5 @@ + #include "ucln_cmn.h" + #include "ustr_imp.h" ++#include "charstr.h" + + U_CDECL_BEGIN +@@ -57,4 +58,10 @@ + static UHashtable *gDefaultLocalesHashT = NULL; + static Locale *gDefaultLocale = NULL; ++ ++/** ++ * \def ULOC_STRING_LIMIT ++ * strings beyond this value crash in CharString ++ */ ++#define ULOC_STRING_LIMIT 357913941 + + U_NAMESPACE_END +@@ -284,5 +291,5 @@ + else + { +- MaybeStackArray togo; ++ UErrorCode status = U_ZERO_ERROR; + int32_t size = 0; + int32_t lsize = 0; +@@ -290,5 +297,4 @@ + int32_t vsize = 0; + int32_t ksize = 0; +- char *p; + + // Calculate the size of the resulting string. +@@ -298,6 +304,12 @@ + { + lsize = (int32_t)uprv_strlen(newLanguage); ++ if ( lsize < 0 || lsize > ULOC_STRING_LIMIT ) { // int32 wrap ++ setToBogus(); ++ return; ++ } + size = lsize; + } ++ ++ CharString togo(newLanguage, lsize, status); // start with newLanguage + + // _Country +@@ -305,4 +317,8 @@ + { + csize = (int32_t)uprv_strlen(newCountry); ++ if ( csize < 0 || csize > ULOC_STRING_LIMIT ) { // int32 wrap ++ setToBogus(); ++ return; ++ } + size += csize; + } +@@ -319,4 +335,8 @@ + // remove trailing _'s + vsize = (int32_t)uprv_strlen(newVariant); ++ if ( vsize < 0 || vsize > ULOC_STRING_LIMIT ) { // int32 wrap ++ setToBogus(); ++ return; ++ } + while( (vsize>1) && (newVariant[vsize-1] == SEP_CHAR) ) + { +@@ -343,48 +363,34 @@ + { + ksize = (int32_t)uprv_strlen(newKeywords); ++ if ( ksize < 0 || ksize > ULOC_STRING_LIMIT ) { ++ setToBogus(); ++ return; ++ } + size += ksize + 1; + } + +- ++ if (size < 0) { ++ setToBogus(); ++ return; ++ } + // NOW we have the full locale string.. +- +- /*if the whole string is longer than our internal limit, we need +- to go to the heap for temporary buffers*/ +- if (size >= togo.getCapacity()) +- { +- // If togo_heap could not be created, initialize with default settings. +- if (togo.resize(size+1) == NULL) { +- init(NULL, FALSE); +- } +- } +- +- togo[0] = 0; +- + // Now, copy it back. +- p = togo.getAlias(); +- if ( lsize != 0 ) +- { +- uprv_strcpy(p, newLanguage); +- p += lsize; +- } ++ ++ // newLanguage is already copied + + if ( ( vsize != 0 ) || (csize != 0) ) // at least: __v + { // ^ +- *p++ = SEP_CHAR; ++ togo.append(SEP_CHAR, status); + } + + if ( csize != 0 ) + { +- uprv_strcpy(p, newCountry); +- p += csize; ++ togo.append(newCountry, status); + } + + if ( vsize != 0) + { +- *p++ = SEP_CHAR; // at least: __v +- +- uprv_strncpy(p, newVariant, vsize); // Must use strncpy because +- p += vsize; // of trimming (above). +- *p = 0; // terminate ++ togo.append(SEP_CHAR, status) ++ .append(newVariant, vsize, status); + } + +@@ -392,19 +398,23 @@ + { + if (uprv_strchr(newKeywords, '=')) { +- *p++ = '@'; /* keyword parsing */ ++ togo.append('@', status); /* keyword parsing */ + } + else { +- *p++ = '_'; /* Variant parsing with a script */ ++ togo.append('_', status); /* Variant parsing with a script */ + if ( vsize == 0) { +- *p++ = '_'; /* No country found */ ++ togo.append('_', status); /* No country found */ + } + } +- uprv_strcpy(p, newKeywords); +- p += ksize; +- } +- ++ togo.append(newKeywords, status); ++ } ++ ++ if (U_FAILURE(status)) { ++ // Something went wrong with appending, etc. ++ setToBogus(); ++ return; ++ } + // Parse it, because for example 'language' might really be a complete + // string. +- init(togo.getAlias(), FALSE); ++ init(togo.data(), FALSE); + } + } +Index: source/test/intltest/numfmtst.cpp +=================================================================== +--- a/source/test/intltest/numfmtst.cpp (revision 39353) ++++ b/source/test/intltest/numfmtst.cpp (revision 39356) +@@ -2421,9 +2421,10 @@ + const char *localeName = badLocales[i]; + Locale locBad(localeName); ++ TEST_ASSERT_TRUE(!locBad.isBogus()); + UErrorCode status = U_ZERO_ERROR; + UnicodeString intlCurrencySymbol((UChar)0xa4); + + intlCurrencySymbol.append((UChar)0xa4); +- ++ + logln("Current locale is %s", Locale::getDefault().getName()); + Locale::setDefault(locBad, status); diff --git a/CVE-2017-14952.patch b/CVE-2017-14952.patch new file mode 100644 index 0000000..ab2e59b --- /dev/null +++ b/CVE-2017-14952.patch @@ -0,0 +1,10 @@ +Index: source/i18n/zonemeta.cpp +=================================================================== +--- a/source/i18n/zonemeta.cpp (revision 40283) ++++ b/source/i18n/zonemeta.cpp (revision 40324) +@@ -682,5 +682,4 @@ + if (U_FAILURE(status)) { + delete mzMappings; +- deleteOlsonToMetaMappingEntry(entry); + uprv_free(entry); + break; diff --git a/CVE-2017-15422.patch b/CVE-2017-15422.patch new file mode 100644 index 0000000..d194adf --- /dev/null +++ b/CVE-2017-15422.patch @@ -0,0 +1,118 @@ +Index: icu4c/source/i18n/gregoimp.cpp +=================================================================== +--- icu4c/source/i18n/gregoimp.cpp (revision 40653) ++++ icu4c/source/i18n/gregoimp.cpp (revision 40654) +@@ -29,6 +29,11 @@ int32_t ClockMath::floorDivide(int32_t n + numerator / denominator : ((numerator + 1) / denominator) - 1; + } + ++int64_t ClockMath::floorDivide(int64_t numerator, int64_t denominator) { ++ return (numerator >= 0) ? ++ numerator / denominator : ((numerator + 1) / denominator) - 1; ++} ++ + int32_t ClockMath::floorDivide(double numerator, int32_t denominator, + int32_t& remainder) { + double quotient; +Index: icu4c/source/i18n/gregoimp.h +=================================================================== +--- icu4c/source/i18n/gregoimp.h (revision 40653) ++++ icu4c/source/i18n/gregoimp.h (revision 40654) +@@ -39,6 +39,17 @@ class ClockMath { + static int32_t floorDivide(int32_t numerator, int32_t denominator); + + /** ++ * Divide two integers, returning the floor of the quotient. ++ * Unlike the built-in division, this is mathematically ++ * well-behaved. E.g., -1/4 => 0 but ++ * floorDivide(-1,4) => -1. ++ * @param numerator the numerator ++ * @param denominator a divisor which must be != 0 ++ * @return the floor of the quotient ++ */ ++ static int64_t floorDivide(int64_t numerator, int64_t denominator); ++ ++ /** + * Divide two numbers, returning the floor of the quotient. + * Unlike the built-in division, this is mathematically + * well-behaved. E.g., -1/4 => 0 but +Index: icu4c/source/i18n/persncal.cpp +=================================================================== +--- icu4c/source/i18n/persncal.cpp (revision 40653) ++++ icu4c/source/i18n/persncal.cpp (revision 40654) +@@ -211,7 +211,7 @@ void PersianCalendar::handleComputeField + int32_t year, month, dayOfMonth, dayOfYear; + + int32_t daysSinceEpoch = julianDay - PERSIAN_EPOCH; +- year = 1 + ClockMath::floorDivide(33 * daysSinceEpoch + 3, 12053); ++ year = 1 + (int32_t)ClockMath::floorDivide(33 * (int64_t)daysSinceEpoch + 3, (int64_t)12053); + + int32_t farvardin1 = 365 * (year - 1) + ClockMath::floorDivide(8 * year + 21, 33); + dayOfYear = (daysSinceEpoch - farvardin1); // 0-based +Index: icu4c/source/test/intltest/calregts.cpp +=================================================================== +--- icu4c/source/test/intltest/calregts.cpp (revision 40653) ++++ icu4c/source/test/intltest/calregts.cpp (revision 40654) +@@ -10,6 +10,7 @@ + + #include "calregts.h" + ++#include "unicode/calendar.h" + #include "unicode/gregocal.h" + #include "unicode/simpletz.h" + #include "unicode/smpdtfmt.h" +@@ -88,6 +89,7 @@ CalendarRegressionTest::runIndexedTest( + CASE(48,TestT8596); + CASE(49,Test9019); + CASE(50,TestT9452); ++ CASE(51,TestPersianCalOverflow); + default: name = ""; break; + } + } +@@ -2944,4 +2946,34 @@ void CalendarRegressionTest::TestT9452(v + } + } + ++/** ++ * @bug ticket 13454 ++ */ ++void CalendarRegressionTest::TestPersianCalOverflow(void) { ++ const char* localeID = "bs_Cyrl@calendar=persian"; ++ UErrorCode status = U_ZERO_ERROR; ++ Calendar* cal = Calendar::createInstance(Locale(localeID), status); ++ if(U_FAILURE(status)) { ++ dataerrln("FAIL: Calendar::createInstance for localeID %s: %s", localeID, u_errorName(status)); ++ } else { ++ int32_t maxMonth = cal->getMaximum(UCAL_MONTH); ++ int32_t maxDayOfMonth = cal->getMaximum(UCAL_DATE); ++ int32_t jd, month, dayOfMonth; ++ for (jd = 67023580; jd <= 67023584; jd++) { // year 178171, int32_t overflow if jd >= 67023582 ++ status = U_ZERO_ERROR; ++ cal->clear(); ++ cal->set(UCAL_JULIAN_DAY, jd); ++ month = cal->get(UCAL_MONTH, status); ++ dayOfMonth = cal->get(UCAL_DATE, status); ++ if ( U_FAILURE(status) ) { ++ errln("FAIL: Calendar->get MONTH/DATE for localeID %s, julianDay %d, status %s\n", localeID, jd, u_errorName(status)); ++ } else if (month > maxMonth || dayOfMonth > maxDayOfMonth) { ++ errln("FAIL: localeID %s, julianDay %d; maxMonth %d, got month %d; maxDayOfMonth %d, got dayOfMonth %d\n", ++ localeID, jd, maxMonth, month, maxDayOfMonth, dayOfMonth); ++ } ++ } ++ delete cal; ++ } ++} ++ + #endif /* #if !UCONFIG_NO_FORMATTING */ +Index: icu4c/source/test/intltest/calregts.h +=================================================================== +--- icu4c/source/test/intltest/calregts.h (revision 40653) ++++ icu4c/source/test/intltest/calregts.h (revision 40654) +@@ -75,6 +75,7 @@ public: + void TestT8596(void); + void Test9019(void); + void TestT9452(void); ++ void TestPersianCalOverflow(void); + + void printdate(GregorianCalendar *cal, const char *string); + void dowTest(UBool lenient) ; diff --git a/CVE-2017-7867_CVE-2017-7868.patch b/CVE-2017-7867_CVE-2017-7868.patch new file mode 100644 index 0000000..b898b02 --- /dev/null +++ b/CVE-2017-7867_CVE-2017-7868.patch @@ -0,0 +1,176 @@ +Index: icu/source/test/intltest/utxttest.h +=================================================================== +--- icu/source/test/intltest/utxttest.h (revision 39670) ++++ icu/source/test/intltest/utxttest.h (revision 39671) +@@ -36,6 +36,7 @@ + void Ticket10562(); + void Ticket10983(); + void Ticket12130(); ++ void Ticket12888(); + + private: + struct m { // Map between native indices & code points. +Index: icu/source/test/intltest/utxttest.cpp +=================================================================== +--- icu/source/test/intltest/utxttest.cpp (revision 39670) ++++ icu/source/test/intltest/utxttest.cpp (revision 39671) +@@ -65,6 +65,8 @@ + if (exec) Ticket10983(); break; + case 7: name = "Ticket12130"; + if (exec) Ticket12130(); break; ++ case 8: name = "Ticket12888"; ++ if (exec) Ticket12888(); break; + default: name = ""; break; + } + } +@@ -1581,3 +1583,63 @@ + } + utext_close(&ut); + } ++ ++// Ticket 12888: bad handling of illegal utf-8 containing many instances of the archaic, now illegal, ++// six byte utf-8 forms. Original implementation had an assumption that ++// there would be at most three utf-8 bytes per UTF-16 code unit. ++// The five and six byte sequences map to a single replacement character. ++ ++void UTextTest::Ticket12888() { ++ const char *badString = ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80" ++ "\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80\xfd\x80\x80\x80\x80\x80"; ++ ++ UErrorCode status = U_ZERO_ERROR; ++ LocalUTextPointer ut(utext_openUTF8(NULL, badString, -1, &status)); ++ TEST_SUCCESS(status); ++ for (;;) { ++ UChar32 c = utext_next32(ut.getAlias()); ++ if (c == U_SENTINEL) { ++ break; ++ } ++ } ++ int32_t endIdx = utext_getNativeIndex(ut.getAlias()); ++ if (endIdx != (int32_t)strlen(badString)) { ++ errln("%s:%d expected=%d, actual=%d", __FILE__, __LINE__, strlen(badString), endIdx); ++ return; ++ } ++ ++ for (int32_t prevIndex = endIdx; prevIndex>0;) { ++ UChar32 c = utext_previous32(ut.getAlias()); ++ int32_t currentIndex = utext_getNativeIndex(ut.getAlias()); ++ if (c != 0xfffd) { ++ errln("%s:%d (expected, actual, index) = (%d, %d, %d)\n", ++ __FILE__, __LINE__, 0xfffd, c, currentIndex); ++ break; ++ } ++ if (currentIndex != prevIndex - 6) { ++ errln("%s:%d: wrong index. Expected, actual = %d, %d", ++ __FILE__, __LINE__, prevIndex - 6, currentIndex); ++ break; ++ } ++ prevIndex = currentIndex; ++ } ++} +Index: icu/source/common/utext.cpp +=================================================================== +--- icu/source/common/utext.cpp (revision 39670) ++++ icu/source/common/utext.cpp (revision 39671) +@@ -845,9 +845,15 @@ + //------------------------------------------------------------------------------ + + // Chunk size. +-// Must be less than 85, because of byte mapping from UChar indexes to native indexes. +-// Worst case is three native bytes to one UChar. (Supplemenaries are 4 native bytes +-// to two UChars.) ++// Must be less than 42 (256/6), because of byte mapping from UChar indexes to native indexes. ++// Worst case there are six UTF-8 bytes per UChar. ++// obsolete 6 byte form fd + 5 trails maps to fffd ++// obsolete 5 byte form fc + 4 trails maps to fffd ++// non-shortest 4 byte forms maps to fffd ++// normal supplementaries map to a pair of utf-16, two utf8 bytes per utf-16 unit ++// mapToUChars array size must allow for the worst case, 6. ++// This could be brought down to 4, by treating fd and fc as pure illegal, ++// rather than obsolete lead bytes. But that is not compatible with the utf-8 access macros. + // + enum { UTF8_TEXT_CHUNK_SIZE=32 }; + +@@ -887,7 +893,7 @@ + // Requires two extra slots, + // one for a supplementary starting in the last normal position, + // and one for an entry for the buffer limit position. +- uint8_t mapToUChars[UTF8_TEXT_CHUNK_SIZE*3+6]; // Map native offset from bufNativeStart to ++ uint8_t mapToUChars[UTF8_TEXT_CHUNK_SIZE*6+6]; // Map native offset from bufNativeStart to + // correspoding offset in filled part of buf. + int32_t align; + }; +@@ -1030,6 +1036,7 @@ + // Requested index is in this buffer. + u8b = (UTF8Buf *)ut->p; // the current buffer + mapIndex = ix - u8b->toUCharsMapStart; ++ U_ASSERT(mapIndex < (int32_t)sizeof(UTF8Buf::mapToUChars)); + ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx; + return TRUE; + +@@ -1296,6 +1303,10 @@ + // Can only do this if the incoming index is somewhere in the interior of the string. + // If index is at the end, there is no character there to look at. + if (ix != ut->b) { ++ // Note: this function will only move the index back if it is on a trail byte ++ // and there is a preceding lead byte and the sequence from the lead ++ // through this trail could be part of a valid UTF-8 sequence ++ // Otherwise the index remains unchanged. + U8_SET_CP_START(s8, 0, ix); + } + +@@ -1309,7 +1320,10 @@ + UChar *buf = u8b->buf; + uint8_t *mapToNative = u8b->mapToNative; + uint8_t *mapToUChars = u8b->mapToUChars; +- int32_t toUCharsMapStart = ix - (UTF8_TEXT_CHUNK_SIZE*3 + 1); ++ int32_t toUCharsMapStart = ix - sizeof(UTF8Buf::mapToUChars) + 1; ++ // Note that toUCharsMapStart can be negative. Happens when the remaining ++ // text from current position to the beginning is less than the buffer size. ++ // + 1 because mapToUChars must have a slot at the end for the bufNativeLimit entry. + int32_t destIx = UTF8_TEXT_CHUNK_SIZE+2; // Start in the overflow region + // at end of buffer to leave room + // for a surrogate pair at the +@@ -1336,6 +1350,7 @@ + if (c<0x80) { + // Special case ASCII range for speed. + buf[destIx] = (UChar)c; ++ U_ASSERT(toUCharsMapStart <= srcIx); + mapToUChars[srcIx - toUCharsMapStart] = (uint8_t)destIx; + mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart); + } else { +@@ -1365,6 +1380,7 @@ + do { + mapToUChars[sIx-- - toUCharsMapStart] = (uint8_t)destIx; + } while (sIx >= srcIx); ++ U_ASSERT(toUCharsMapStart <= (srcIx+1)); + + // Set native indexing limit to be the current position. + // We are processing a non-ascii, non-native-indexing char now; +@@ -1539,6 +1555,7 @@ + U_ASSERT(index>=ut->chunkNativeStart+ut->nativeIndexingLimit); + U_ASSERT(index<=ut->chunkNativeLimit); + int32_t mapIndex = index - u8b->toUCharsMapStart; ++ U_ASSERT(mapIndex < (int32_t)sizeof(UTF8Buf::mapToUChars)); + int32_t offset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx; + U_ASSERT(offset>=0 && offset<=ut->chunkLength); + return offset; diff --git a/CVE-2020-10531.patch b/CVE-2020-10531.patch new file mode 100644 index 0000000..f2a669a --- /dev/null +++ b/CVE-2020-10531.patch @@ -0,0 +1,44 @@ +From b7d08bc04a4296982fcef8b6b8a354a9e4e7afca Mon Sep 17 00:00:00 2001 +From: Frank Tang +Date: Sat, 1 Feb 2020 02:39:04 +0000 +Subject: [PATCH] ICU-20958 Prevent SEGV_MAPERR in append + +See #971 +--- + source/common/unistr.cpp | 6 ++- + +diff --git a/source/common/unistr.cpp b/source/common/unistr.cpp +index 901bb3358ba..077b4d6ef20 100644 +--- a/source/common/unistr.cpp ++++ b/source/common/unistr.cpp +@@ -73,6 +73,17 @@ print(const UChar *s, + // END DEBUGGING + #endif + ++// Adding this function as support of CVE-2020-10531 ++// since this version has not uprv_add32_overflow ++// implement it here. ++UBool uprv_add32_overflow(int32_t a, int32_t b, int32_t* res) { ++ int64_t a64 = static_cast(a); ++ int64_t b64 = static_cast(b); ++ int64_t res64 = a64 + b64; ++ *res = static_cast(res64); ++ return res64 != *res; ++} ++ + // Local function definitions for now + + // need to copy areas that may overlap +@@ -1510,7 +1510,11 @@ UnicodeString::doAppend(const UChar *src + } + + 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, newLength + (newLength >> 2) + kGrowSize)) { diff --git a/icu.spec b/icu.spec index abfe308..d78df79 100644 --- a/icu.spec +++ b/icu.spec @@ -17,7 +17,7 @@ Summary: International Components for Unicode Name: icu Epoch: 1 Version: 57.1 -Release: 8 +Release: 9 License: MIT Group: System/Libraries Url: http://www.icu-project.org/index.html @@ -29,6 +29,14 @@ Patch1: icu-57.1-ICU-12936.patch Patch10: icu.7601.Indic-ccmp.patch Patch11: icu.8198.revert.icu5431.patch Patch12: icu.8800.freeserif.crash.patch +# From Debian +Patch20: CVE-2016-6293.patch +Patch21: CVE-2016-7415.patch +Patch22: CVE-2017-7867_CVE-2017-7868.patch +Patch23: CVE-2017-14952.patch +Patch24: CVE-2017-15422.patch +Patch25: CVE-2020-10531.patch + BuildRequires: doxygen %description @@ -213,6 +221,12 @@ Development files and headers for the International Components for Unicode. %patch10 -p1 %patch11 -p2 -R %patch12 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 mkdir -p docs cd docs