From: Ondřej Surý Date: Wed, 26 Jan 2022 11:08:10 +0000 (+0100) Subject: Add more validity checks to the isc_time API X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=fe9703b8fc75e421c16775357a837fde4cfcd8ed;p=thirdparty%2Fbind9.git Add more validity checks to the isc_time API This commits backport few things from the 64-bit time branch: * Add ISC_VALID_TIME() and ISC_VALID_INTERVAL() macros that checks the valid range for nanoseconds * Add more specific buffer sizes for formatting the dates and require the buffers passed to the formatting functions to be at least that big. * When error happens when formatting the string, always return a valid buffer with formatted mock datetime string instead of garbage. Because the formatting functions doesn't return status, the caller could print garbage (unterminated string). --- diff --git a/lib/isc/include/isc/time.h b/lib/isc/include/isc/time.h index 9fa025c9f4a..dcc2285de1e 100644 --- a/lib/isc/include/isc/time.h +++ b/lib/isc/include/isc/time.h @@ -30,6 +30,15 @@ constexpr unsigned int US_PER_SEC = 1000 * 1000; constexpr unsigned int NS_PER_MS = 1000 * 1000; constexpr unsigned int NS_PER_SEC = 1000 * 1000 * 1000; +#define ISC_FORMATTIMESTAMP_SIZE sizeof("99-Bad-9999 99:99:99.999") +#define ISC_FORMATISO8601L_SIZE sizeof("9999-99-99T99:99:99") +#define ISC_FORMATISO8601LMS_SIZE sizeof("9999-99-99T99:99:99.999") +#define ISC_FORMATISO8601_SIZE sizeof("9999-99-99T99:99:99Z") +#define ISC_FORMATISO8601MS_SIZE sizeof("9999-99-99T99:99:99.999Z") +#define ISC_FORMATISO8601US_SIZE sizeof("9999-99-99T99:99:99.999999Z") +#define ISC_FORMATISO8601TZMS_SIZE sizeof("9999-99-99T99:99:99.999+99:99") +#define ISC_FORMATSHORTTIMESTAMP_SIZE sizeof("99999999999999999") + /* * ISC_FORMATHTTPTIMESTAMP_SIZE needs to be 30 in C locale and potentially * more for other locales to handle longer national abbreviations when diff --git a/lib/isc/time.c b/lib/isc/time.c index 90afabfc420..9806298e676 100644 --- a/lib/isc/time.c +++ b/lib/isc/time.c @@ -30,6 +30,10 @@ #include #include +#define ISC_VALID_TIME(t) (t != NULL && t->nanoseconds < NS_PER_SEC) + +#define ISC_VALID_INTERVAL ISC_VALID_TIME + #if defined(CLOCK_REALTIME) #define CLOCKSOURCE_HIRES CLOCK_REALTIME #endif /* #if defined(CLOCK_REALTIME) */ @@ -70,8 +74,7 @@ isc_time_settoepoch(isc_time_t *t) { bool isc_time_isepoch(const isc_time_t *t) { - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); if (t->seconds == 0 && t->nanoseconds == 0) { return true; @@ -130,27 +133,26 @@ isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) { struct timespec ts; REQUIRE(t != NULL); - REQUIRE(i != NULL); - INSIST(i->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_INTERVAL(i)); if (clock_gettime(CLOCKSOURCE, &ts) == -1) { - UNEXPECTED_SYSERROR(errno, "clock_gettime()"); + char strbuf[ISC_STRERRORSIZE]; + strerror_r(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR("%s", strbuf); return ISC_R_UNEXPECTED; } - if (ts.tv_sec < 0 || ts.tv_nsec < 0 || ts.tv_nsec >= (long)NS_PER_SEC) { + if ((ts.tv_sec < 0 || ts.tv_sec > UINT_MAX) || + (ts.tv_nsec < 0 || ts.tv_nsec >= (long)NS_PER_SEC)) + { return ISC_R_UNEXPECTED; } /* * Ensure the resulting seconds value fits in the size of an - * unsigned int. (It is written this way as a slight optimization; - * note that even if both values == INT_MAX, then when added - * and getting another 1 added below the result is UINT_MAX.) + * unsigned int. */ - if ((ts.tv_sec > INT_MAX || i->seconds > INT_MAX) && - ((long long)ts.tv_sec + i->seconds > UINT_MAX)) - { + if ((unsigned int)ts.tv_sec > UINT_MAX - i->seconds) { return ISC_R_RANGE; } @@ -166,8 +168,8 @@ isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) { int isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) { - REQUIRE(t1 != NULL && t2 != NULL); - INSIST(t1->nanoseconds < NS_PER_SEC && t2->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t1)); + REQUIRE(ISC_VALID_TIME(t2)); if (t1->seconds < t2->seconds) { return -1; @@ -186,8 +188,9 @@ isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) { isc_result_t isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) { - REQUIRE(t != NULL && i != NULL && result != NULL); - REQUIRE(t->nanoseconds < NS_PER_SEC && i->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); + REQUIRE(ISC_VALID_INTERVAL(i)); + REQUIRE(result != NULL); /* Seconds */ if (ckd_add(&result->seconds, t->seconds, i->seconds)) { @@ -210,8 +213,9 @@ isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) { isc_result_t isc_time_subtract(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) { - REQUIRE(t != NULL && i != NULL && result != NULL); - REQUIRE(t->nanoseconds < NS_PER_SEC && i->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); + REQUIRE(ISC_VALID_INTERVAL(i)); + REQUIRE(result != NULL); /* Seconds */ if (ckd_sub(&result->seconds, t->seconds, i->seconds)) { @@ -237,8 +241,8 @@ uint64_t isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) { uint64_t i1, i2, i3; - REQUIRE(t1 != NULL && t2 != NULL); - INSIST(t1->nanoseconds < NS_PER_SEC && t2->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t1)); + REQUIRE(ISC_VALID_TIME(t2)); i1 = (uint64_t)t1->seconds * NS_PER_SEC + t1->nanoseconds; i2 = (uint64_t)t2->seconds * NS_PER_SEC + t2->nanoseconds; @@ -259,8 +263,7 @@ isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) { uint32_t isc_time_seconds(const isc_time_t *t) { - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); return (uint32_t)t->seconds; } @@ -269,8 +272,7 @@ isc_result_t isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) { time_t seconds; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); /* * Ensure that the number of seconds represented by t->seconds @@ -305,17 +307,14 @@ isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) { uint32_t isc_time_nanoseconds(const isc_time_t *t) { - REQUIRE(t != NULL); - - ENSURE(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); return (uint32_t)t->nanoseconds; } uint32_t isc_time_miliseconds(const isc_time_t *t) { - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); return (t->seconds * MS_PER_SEC) + (t->nanoseconds / NS_PER_MS); } @@ -326,19 +325,17 @@ isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) { unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATTIMESTAMP_SIZE); now = (time_t)t->seconds; flen = strftime(buf, len, "%d-%b-%Y %X", localtime_r(&now, &tm)); - INSIST(flen < len); - if (flen != 0) { + if (flen == 0) { + strlcpy(buf, "99-Bad-9999 99:99:99.999", len); + } else { snprintf(buf + flen, len - flen, ".%03u", t->nanoseconds / NS_PER_MS); - } else { - strlcpy(buf, "99-Bad-9999 99:99:99.999", len); } } @@ -348,10 +345,9 @@ isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) { unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATHTTPTIMESTAMP_SIZE); /* * 5 spaces, 1 comma, 3 GMT, 2 %d, 4 %Y, 8 %H:%M:%S, 3+ %a, 3+ @@ -360,7 +356,9 @@ isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) { now = (time_t)t->seconds; flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime_r(&now, &tm)); - INSIST(flen < len); + if (flen == 0) { + strlcpy(buf, "Bad, 99 Bad 9999 99:99:99 GMT", len); + } } isc_result_t @@ -390,15 +388,15 @@ isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len) { unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATISO8601LMS_SIZE); now = (time_t)t->seconds; flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", localtime_r(&now, &tm)); - INSIST(flen < len); - if (flen > 0U && len - flen >= 6) { + if (flen == 0) { + strlcpy(buf, "9999-99-99T99:99:99.999", len); + } else { snprintf(buf + flen, len - flen, ".%03u", t->nanoseconds / NS_PER_MS); } @@ -412,10 +410,9 @@ isc_time_formatISO8601TZms(const isc_time_t *t, char *buf, unsigned int len) { unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATISO8601TZMS_SIZE); now = (time_t)t->seconds; flen = strftime(strftime_buf, len, "%Y-%m-%dT%H:%M:%S.xxx%z", @@ -438,14 +435,15 @@ isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) { unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATISO8601_SIZE); now = (time_t)t->seconds; flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&now, &tm)); - INSIST(flen < len); + if (flen == 0) { + strlcpy(buf, "9999-99-99T99:99:99Z", len); + } } void @@ -454,16 +452,15 @@ isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len) { unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATISO8601MS_SIZE); now = (time_t)t->seconds; - flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&now, &tm)); - INSIST(flen < len); - if (flen > 0U && len - flen >= 5) { - flen -= 1; /* rewind one character (Z) */ + flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", gmtime_r(&now, &tm)); + if (flen == 0) { + strlcpy(buf, "9999-99-99T99:99:99.999Z", len); + } else { snprintf(buf + flen, len - flen, ".%03uZ", t->nanoseconds / NS_PER_MS); } @@ -475,16 +472,15 @@ isc_time_formatISO8601us(const isc_time_t *t, char *buf, unsigned int len) { unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATISO8601US_SIZE); now = (time_t)t->seconds; - flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&now, &tm)); - INSIST(flen < len); - if (flen > 0U && len - flen >= 5) { - flen -= 1; /* rewind one character (Z) */ + flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", gmtime_r(&now, &tm)); + if (flen == 0) { + strlcpy(buf, "9999-99-99T99:99:99.999999Z", len); + } else { snprintf(buf + flen, len - flen, ".%06uZ", t->nanoseconds / NS_PER_US); } @@ -497,15 +493,15 @@ isc_time_formatshorttimestamp(const isc_time_t *t, char *buf, unsigned int flen; struct tm tm; - REQUIRE(t != NULL); - INSIST(t->nanoseconds < NS_PER_SEC); + REQUIRE(ISC_VALID_TIME(t)); REQUIRE(buf != NULL); - REQUIRE(len > 0); + REQUIRE(len >= ISC_FORMATSHORTTIMESTAMP_SIZE); now = (time_t)t->seconds; flen = strftime(buf, len, "%Y%m%d%H%M%S", gmtime_r(&now, &tm)); - INSIST(flen < len); - if (flen > 0U && len - flen >= 5) { + if (flen == 0) { + strlcpy(buf, "99999999999999999", len); + } else { snprintf(buf + flen, len - flen, "%03u", t->nanoseconds / NS_PER_MS); }