lkundrak / rpms / chrony

Forked from rpms/chrony 4 years ago
Clone
Blob Blame History Raw
commit d0b24860363a3704e28569ce9a6987717834edea
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date:   Tue Dec 5 11:08:24 2017 +0100

    client: don't call select() with invalid timeout
    
    If the system clock was stepped forward after chronyc sent a request and
    before it read the clock in order to calculate the receive timeout,
    select() could be called with a negative timeout, which resulted in an
    infinite loop waiting for select() to succeed.
    
    Fix the submit_request() function to not call select() with a negative
    timeout. Also, return immediately on any error of select().

diff --git a/client.c b/client.c
index 5c3a99e..4e23158 100644
--- a/client.c
+++ b/client.c
@@ -1394,9 +1394,16 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
 
     timeout = initial_timeout / 1000.0 * (1U << (n_attempts - 1)) -
               UTI_DiffTimespecsToDouble(&ts_now, &ts_start);
-    UTI_DoubleToTimeval(timeout, &tv);
     DEBUG_LOG("Timeout %f seconds", timeout);
 
+    /* Avoid calling select() with an invalid timeout */
+    if (timeout <= 0.0) {
+      new_attempt = 1;
+      continue;
+    }
+
+    UTI_DoubleToTimeval(timeout, &tv);
+
     FD_ZERO(&rdfd);
     FD_ZERO(&wrfd);
     FD_ZERO(&exfd);
@@ -1410,6 +1417,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
 
     if (select_status < 0) {
       DEBUG_LOG("select failed : %s", strerror(errno));
+      return 0;
     } else if (select_status == 0) {
       /* Timeout must have elapsed, try a resend? */
       new_attempt = 1;

commit 6863e43269fe27ce2744eb643295f31c00ec176d
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date:   Tue Dec 12 11:03:04 2017 +0100

    client: avoid reading clock after sending request
    
    If chronyc sent a request which caused chronyd to step the clock (e.g.
    makestep, settime) and the second reading of the clock before calling
    select() to wait for a response happened after the clock was stepped, a
    new request could be sent immediately and chronyd would process the same
    command twice. If the second request failed (e.g. a settime request too
    close to the first request), chronyc would report an error.
    
    Change the submit_request() function to read the clock only once per
    select() to wait for the first response even when the clock was stepped.

diff --git a/client.c b/client.c
index a04dcb8..7d1e346 100644
--- a/client.c
+++ b/client.c
@@ -1347,15 +1347,15 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
   new_attempt = 1;
 
   do {
+    if (gettimeofday(&tv, NULL))
+      return 0;
+
     if (new_attempt) {
       new_attempt = 0;
 
       if (n_attempts > max_retries)
         return 0;
 
-      if (gettimeofday(&tv, NULL))
-        return 0;
-
       UTI_TimevalToTimespec(&tv, &ts_start);
 
       UTI_GetRandomBytes(&request->sequence, sizeof (request->sequence));
@@ -1383,9 +1383,6 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
       DEBUG_LOG("Sent %d bytes", command_length);
     }
 
-    if (gettimeofday(&tv, NULL))
-      return 0;
-
     UTI_TimevalToTimespec(&tv, &ts_now);
 
     /* Check if the clock wasn't stepped back */