]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
[master] Capped large interval times to avoid fatal timer errors
authorThomas Markwalder <tmark@isc.org>
Wed, 26 Apr 2017 19:26:17 +0000 (15:26 -0400)
committerThomas Markwalder <tmark@isc.org>
Wed, 26 Apr 2017 19:26:17 +0000 (15:26 -0400)
RELNOTES
common/dispatch.c

index a6c96f8d6b8557fcb82510515c93b04f3c4ea8fc..12f34481f94501f1d57acc71e9bfe26214e6c89e 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -166,6 +166,11 @@ by Eric Young (eay@cryptsoft.com).
   for expiry in the script environment.
   [ISC-Bugs #43326]
 
+- Common timer logic was modified to cap the maximum timeout values at
+  0x7FFFFFFF - 1. Values larger than that were causing fatal timer out of
+  range errors on 64-bit platforms. Thanks to Jiri Popelka at Red Hat for
+  reporting the issue.
+  [ISC-Bugs #28038]
 
                        Changes since 4.3.0 (bug fixes)
 
index c75a003b2879d762812960a5e7ae55e799d96a8e..3ca3749be82a74b72aba129600066733c1479912 100644 (file)
@@ -3,7 +3,7 @@
    Network input dispatcher... */
 
 /*
- * Copyright (c) 2004-2011,2013 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
  * Copyright (c) 1995-2003 by Internet Software Consortium
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -193,7 +193,6 @@ isclib_timer_callback(isc_task_t  *taskp,
 
 /* maximum value for usec */
 #define USEC_MAX 1000000
-#define DHCP_SEC_MAX  0xFFFFFFFF
 
 void add_timeout (when, where, what, ref, unref)
        struct timeval *when;
@@ -255,10 +254,14 @@ void add_timeout (when, where, what, ref, unref)
         * about the usec value, if it's zero we assume the caller didn't care.
         *
         * The ISC timer library doesn't seem to like negative values
-        * and can't accept any values above 4G-1 seconds so we limit
-        * the values to 0 <= value < 4G-1.  We do it before
-        * checking the trace option so that both the trace code and
-        * the working code use the same values.
+        * and on 64-bit systems, isc_time_nowplusinterval() can generate range
+        * errors on values sufficiently larger than 0x7FFFFFFF (TIME_MAX), so
+        * we'll limit the interval to:
+        *
+        *      0 <= interval <= TIME_MAX - 1
+        *
+        * We do it before checking the trace option so that both the trace
+        * code and * the working code use the same values.
         */
 
        sec  = when->tv_sec - cur_tv.tv_sec;
@@ -272,10 +275,11 @@ void add_timeout (when, where, what, ref, unref)
        if (sec < 0) {
                sec  = 0;
                usec = 0;
-       } else if (sec > DHCP_SEC_MAX) {
-               log_error("Timeout requested too large "
-                         "reducing to 2^^32-1");
-               sec = DHCP_SEC_MAX;
+       } else if (sec >= TIME_MAX) {
+               log_error("Timeout requested: %lu is too large, "
+                         "reducing to: %lu (TIME_MAX - 1)", sec,
+                         (unsigned long)(TIME_MAX - 1));
+               sec = TIME_MAX - 1;
                usec = 0;
        } else if (usec < 0) {
                usec = 0;
@@ -288,7 +292,7 @@ void add_timeout (when, where, what, ref, unref)
         * here in case we want to compare timing information
         * for some reason, like debugging.
         */
-       q->when.tv_sec  = cur_tv.tv_sec + (sec & DHCP_SEC_MAX);
+       q->when.tv_sec  = cur_tv.tv_sec + sec;
        q->when.tv_usec = usec;
 
 #if defined (TRACING)
@@ -339,12 +343,12 @@ void add_timeout (when, where, what, ref, unref)
        q->next  = timeouts;
        timeouts = q;
 
-       isc_interval_set(&interval, sec & DHCP_SEC_MAX, usec * 1000);
+       isc_interval_set(&interval, sec, usec * 1000);
        status = isc_time_nowplusinterval(&expires, &interval);
        if (status != ISC_R_SUCCESS) {
                /*
-                * The system time function isn't happy or returned
-                * a value larger than isc_time_t can hold.
+                * The system time function isn't happy. Range errors
+                * should not be possible with the check logic above.
                 */
                log_fatal("Unable to set up timer: %s",
                          isc_result_totext(status));