ICUTimeConversion: Fix buffer overflows and add more error handling.

* Declare databridge buffer lengths in LocaleBackend.
 * Use strcpy instead of strlcpy when writing to databridge buffers
   (this is the first fix for #18598.)
 * Check for overflows and error out when they happen.
 * Verify that ICU actually knows the timezone in question
   and fall back to GMT if it does not (this would also fix that crash.)

Fixes #18598.
This commit is contained in:
Augustin Cavalier 2023-10-28 16:36:12 -04:00
parent c199c568de
commit e8d328979c
2 changed files with 24 additions and 12 deletions

View File

@ -102,12 +102,14 @@ struct LocaleTimeDataBridge {
struct TimeConversionDataBridge { struct TimeConversionDataBridge {
static const int32 kTZNameLength = 64;
private: private:
int localDaylight; int localDaylight;
long localTimezone; long localTimezone;
char* localTZName[2]; char* localTZName[2];
char localTZName0[64]; char localTZName0[kTZNameLength];
char localTZName1[64]; char localTZName1[kTZNameLength];
public: public:
int* addrOfDaylight; int* addrOfDaylight;

View File

@ -113,6 +113,10 @@ done:
if (fTimeZone == NULL) if (fTimeZone == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
UnicodeString temp;
if (fTimeZone->getID(temp) == UCAL_UNKNOWN_ZONE_ID)
goto error;
if (offsetHasBeenSet) { if (offsetHasBeenSet) {
fTimeZone->setRawOffset(*fDataBridge->addrOfTimezone * -1 * 1000); fTimeZone->setRawOffset(*fDataBridge->addrOfTimezone * -1 * 1000);
} else { } else {
@ -121,14 +125,8 @@ done:
UDate nowMillis = 1000 * (UDate)time(NULL); UDate nowMillis = 1000 * (UDate)time(NULL);
UErrorCode icuStatus = U_ZERO_ERROR; UErrorCode icuStatus = U_ZERO_ERROR;
fTimeZone->getOffset(nowMillis, FALSE, rawOffset, dstOffset, icuStatus); fTimeZone->getOffset(nowMillis, FALSE, rawOffset, dstOffset, icuStatus);
if (!U_SUCCESS(icuStatus)) { if (!U_SUCCESS(icuStatus))
*fDataBridge->addrOfTimezone = 0; goto error;
*fDataBridge->addrOfDaylight = false;
strcpy(fDataBridge->addrOfTZName[0], "GMT");
strcpy(fDataBridge->addrOfTZName[1], "GMT");
return B_ERROR;
}
*fDataBridge->addrOfTimezone = -1 * (rawOffset + dstOffset) / 1000; *fDataBridge->addrOfTimezone = -1 * (rawOffset + dstOffset) / 1000;
// we want seconds, not the ms that ICU gives us // we want seconds, not the ms that ICU gives us
} }
@ -137,15 +135,19 @@ done:
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
if (tz != NULL && *tz != ':' && i == 0) { if (tz != NULL && *tz != ':' && i == 0) {
strcpy(fDataBridge->addrOfTZName[0], fTimeZoneID); strlcpy(fDataBridge->addrOfTZName[0], fTimeZoneID,
fDataBridge->kTZNameLength);
} else { } else {
UnicodeString icuString; UnicodeString icuString;
fTimeZone->getDisplayName(i == 1, TimeZone::SHORT, fTimeZone->getDisplayName(i == 1, TimeZone::SHORT,
fTimeData.ICULocaleForStrings(), icuString); fTimeData.ICULocaleForStrings(), icuString);
CheckedArrayByteSink byteSink(fDataBridge->addrOfTZName[i], CheckedArrayByteSink byteSink(fDataBridge->addrOfTZName[i],
sizeof(fTimeZoneID)); fDataBridge->kTZNameLength);
icuString.toUTF8(byteSink); icuString.toUTF8(byteSink);
if (byteSink.Overflowed())
goto error;
// make sure to canonicalize "GMT+00:00" to just "GMT" // make sure to canonicalize "GMT+00:00" to just "GMT"
if (strcmp(fDataBridge->addrOfTZName[i], "GMT+00:00") == 0) if (strcmp(fDataBridge->addrOfTZName[i], "GMT+00:00") == 0)
fDataBridge->addrOfTZName[i][3] = '\0'; fDataBridge->addrOfTZName[i][3] = '\0';
@ -153,6 +155,14 @@ done:
} }
return B_OK; return B_OK;
error:
*fDataBridge->addrOfTimezone = 0;
*fDataBridge->addrOfDaylight = false;
strcpy(fDataBridge->addrOfTZName[0], "GMT");
strcpy(fDataBridge->addrOfTZName[1], "GMT");
return B_ERROR;
} }