2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 22:15:20 +00:00

Fix isc_time_add() overflow

The isc_time_add() could overflow when t.seconds + i.seconds == UINT_MAX
and t.nanoseconds + i.nanoseconds >= NS_PER_S.

Fix the overflow in isc_time_add(), and simplify the ISC_R_RANGE checks
both in isc_time_add() and isc_time_subtract() functions.
This commit is contained in:
Ondřej Surý
2021-10-20 11:22:52 +02:00
committed by Ondřej Surý
parent d09625423c
commit 8c05f12bc8

View File

@@ -228,25 +228,22 @@ isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
isc_result_t isc_result_t
isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) { 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 != NULL && i != NULL && result != NULL);
INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S); REQUIRE(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
/* /* Seconds */
* Ensure the resulting seconds value fits in the size of an if (t->seconds > UINT_MAX - i->seconds) {
* 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.)
*/
if ((t->seconds > INT_MAX || i->seconds > INT_MAX) &&
((long long)t->seconds + i->seconds > UINT_MAX))
{
return (ISC_R_RANGE); return (ISC_R_RANGE);
} }
result->seconds = t->seconds + i->seconds; result->seconds = t->seconds + i->seconds;
/* Nanoseconds */
result->nanoseconds = t->nanoseconds + i->nanoseconds; result->nanoseconds = t->nanoseconds + i->nanoseconds;
if (result->nanoseconds >= NS_PER_S) { if (result->nanoseconds >= NS_PER_S) {
result->seconds++; if (result->seconds == UINT_MAX) {
return (ISC_R_RANGE);
}
result->nanoseconds -= NS_PER_S; result->nanoseconds -= NS_PER_S;
result->seconds++;
} }
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
@@ -256,22 +253,24 @@ isc_result_t
isc_time_subtract(const isc_time_t *t, const isc_interval_t *i, isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
isc_time_t *result) { isc_time_t *result) {
REQUIRE(t != NULL && i != NULL && result != NULL); REQUIRE(t != NULL && i != NULL && result != NULL);
INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S); REQUIRE(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
if ((unsigned int)t->seconds < i->seconds || /* Seconds */
((unsigned int)t->seconds == i->seconds && if (t->seconds < i->seconds) {
t->nanoseconds < i->nanoseconds))
{
return (ISC_R_RANGE); return (ISC_R_RANGE);
} }
result->seconds = t->seconds - i->seconds; result->seconds = t->seconds - i->seconds;
/* Nanoseconds */
if (t->nanoseconds >= i->nanoseconds) { if (t->nanoseconds >= i->nanoseconds) {
result->nanoseconds = t->nanoseconds - i->nanoseconds; result->nanoseconds = t->nanoseconds - i->nanoseconds;
} else { } else {
result->nanoseconds = NS_PER_S - i->nanoseconds + if (result->seconds == 0) {
t->nanoseconds; return (ISC_R_RANGE);
}
result->seconds--; result->seconds--;
result->nanoseconds = NS_PER_S + t->nanoseconds -
i->nanoseconds;
} }
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
@@ -318,20 +317,20 @@ isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) {
/* /*
* Ensure that the number of seconds represented by t->seconds * Ensure that the number of seconds represented by t->seconds
* can be represented by a time_t. Since t->seconds is an unsigned * can be represented by a time_t. Since t->seconds is an
* int and since time_t is mostly opaque, this is trickier than * unsigned int and since time_t is mostly opaque, this is
* it seems. (This standardized opaqueness of time_t is *very* * trickier than it seems. (This standardized opaqueness of
* frustrating; time_t is not even limited to being an integral * time_t is *very* frustrating; time_t is not even limited to
* type.) * being an integral type.)
* *
* The mission, then, is to avoid generating any kind of warning * The mission, then, is to avoid generating any kind of warning
* about "signed versus unsigned" while trying to determine if the * about "signed versus unsigned" while trying to determine if
* the unsigned int t->seconds is out range for tv_sec, which is * the unsigned int t->seconds is out range for tv_sec,
* pretty much only true if time_t is a signed integer of the same * which is pretty much only true if time_t is a signed integer
* size as the return value of isc_time_seconds. * of the same size as the return value of isc_time_seconds.
* *
* If the paradox in the if clause below is true, t->seconds is out * If the paradox in the if clause below is true, t->seconds is
* of range for time_t. * out of range for time_t.
*/ */
seconds = (time_t)t->seconds; seconds = (time_t)t->seconds;
@@ -390,7 +389,8 @@ isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
REQUIRE(len > 0); REQUIRE(len > 0);
/* /*
* 5 spaces, 1 comma, 3 GMT, 2 %d, 4 %Y, 8 %H:%M:%S, 3+ %a, 3+ %b (29+) * 5 spaces, 1 comma, 3 GMT, 2 %d, 4 %Y, 8 %H:%M:%S, 3+ %a, 3+
* %b (29+)
*/ */
now = (time_t)t->seconds; now = (time_t)t->seconds;
flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT",