]> granicus.if.org Git - icu/commitdiff
ICU-21004 Fix buffer over-read in ucal_open
authorJeff Genovy <29107334+jefgen@users.noreply.github.com>
Mon, 2 Mar 2020 00:31:55 +0000 (16:31 -0800)
committerJeff Genovy <29107334+jefgen@users.noreply.github.com>
Thu, 5 Mar 2020 22:09:34 +0000 (14:09 -0800)
The issue shows under valgrind or as an Address Sanitizer failure.

icu4c/source/i18n/ucal.cpp
icu4c/source/test/cintltst/ccaltst.c

index 927b2d369791bd49778d7f6c66201f9b9c0e5b2b..67c51aea2718d3019bf9b0da176cac098f758076 100644 (file)
@@ -154,25 +154,31 @@ ucal_open(  const UChar*  zoneID,
             UCalendarType caltype,
             UErrorCode*   status)
 {
-
-  if(U_FAILURE(*status)) return 0;
+  if (U_FAILURE(*status)) {
+      return nullptr;
+  }
   
-  LocalPointer<TimeZone> zone( (zoneID==NULL) ? TimeZone::createDefault() 
+  LocalPointer<TimeZone> zone( (zoneID==nullptr) ? TimeZone::createDefault() 
       : _createTimeZone(zoneID, len, status), *status);
 
   if (U_FAILURE(*status)) {
-      return NULL;
+      return nullptr;
   }
 
   if ( caltype == UCAL_GREGORIAN ) {
-      char  localeBuf[ULOC_LOCALE_IDENTIFIER_CAPACITY];
-      if ( locale == NULL ) {
+      char localeBuf[ULOC_LOCALE_IDENTIFIER_CAPACITY];
+      if ( locale == nullptr ) {
           locale = uloc_getDefault();
       }
-      uprv_strncpy(localeBuf, locale, ULOC_LOCALE_IDENTIFIER_CAPACITY);
+      int32_t localeLength = static_cast<int32_t>(uprv_strlen(locale));
+      if (localeLength >= ULOC_LOCALE_IDENTIFIER_CAPACITY) {
+          *status = U_ILLEGAL_ARGUMENT_ERROR;
+          return nullptr;
+      }
+      uprv_strcpy(localeBuf, locale);
       uloc_setKeywordValue("calendar", "gregorian", localeBuf, ULOC_LOCALE_IDENTIFIER_CAPACITY, status);
       if (U_FAILURE(*status)) {
-          return NULL;
+          return nullptr;
       }
       return (UCalendar*)Calendar::createInstance(zone.orphan(), Locale(localeBuf), *status);
   }
@@ -182,8 +188,9 @@ ucal_open(  const UChar*  zoneID,
 U_CAPI void U_EXPORT2
 ucal_close(UCalendar *cal)
 {
-
-  delete (Calendar*) cal;
+    if (cal != nullptr) {
+        delete (Calendar*) cal;
+    }
 }
 
 U_CAPI UCalendar* U_EXPORT2 
index 44cf712e0fed4145ea47174e795efb73c8561496..c15d2771e5facc620a83a593783e38985b476b8c 100644 (file)
@@ -37,10 +37,10 @@ void TestGregorianChange(void);
 void TestFieldDifference(void);
 void TestAddRollEra0AndEraBounds(void);
 void TestGetTZTransition(void);
-
 void TestGetWindowsTimeZoneID(void);
 void TestGetTimeZoneIDByWindowsID(void);
 void TestJpnCalAddSetNextEra(void);
+void TestUcalOpenBufferRead(void);
 
 void addCalTest(TestNode** root);
 
@@ -64,6 +64,7 @@ void addCalTest(TestNode** root)
     addTest(root, &TestGetWindowsTimeZoneID, "tsformat/ccaltst/TestGetWindowsTimeZoneID");
     addTest(root, &TestGetTimeZoneIDByWindowsID, "tsformat/ccaltst/TestGetTimeZoneIDByWindowsID");
     addTest(root, &TestJpnCalAddSetNextEra, "tsformat/ccaltst/TestJpnCalAddSetNextEra");
+    addTest(root, &TestUcalOpenBufferRead, "tsformat/ccaltst/TestUcalOpenBufferRead");
 }
 
 /* "GMT" */
@@ -2543,4 +2544,13 @@ void TestJpnCalAddSetNextEra() {
     }
 }
 
+void TestUcalOpenBufferRead() {
+    // ICU-21004: The issue shows under valgrind or as an Address Sanitizer failure.
+    UErrorCode status = U_ZERO_ERROR;
+    // string length: 157 + 1 + 100 = 258
+    const char *localeID = "x-privatebutreallylongtagfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar-foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoorbarfoobarfoo";
+    UCalendar *cal = ucal_open(NULL, 0, localeID, UCAL_GREGORIAN, &status);
+    ucal_close(cal);
+}
+
 #endif /* #if !UCONFIG_NO_FORMATTING */