]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
local: check offset sanity before accumulation
authorMiroslav Lichvar <mlichvar@redhat.com>
Tue, 7 Apr 2015 12:58:58 +0000 (14:58 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Tue, 7 Apr 2015 13:23:47 +0000 (15:23 +0200)
Don't accept an offset that points to time before 1970 or outside the
interval to which is mapped NTP time.

cmdmon.c
local.c
local.h
reference.c
rtc.c
rtc_linux.c
util.c
util.h

index 969098902f2571cc2a1346b07f24cc9711305241..6a8737655a4d5ceffee38355d629f21b9bdde112 100644 (file)
--- a/cmdmon.c
+++ b/cmdmon.c
@@ -1555,8 +1555,11 @@ handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message)
 static void
 handle_make_step(CMD_Request *rx_message, CMD_Reply *tx_message)
 {
-  LCL_MakeStep();
-  tx_message->status = htons(STT_SUCCESS);
+  if (!LCL_MakeStep()) {
+    tx_message->status = htons(STT_FAILED);
+  } else {
+    tx_message->status = htons(STT_SUCCESS);
+  }
 }
 
 /* ================================================== */
diff --git a/local.c b/local.c
index e3018022941becbf09807f7b5e84a1dad94297f7..f81c35d6c57bdfdf5bb01e0fc1483ef5f5277d9f 100644 (file)
--- a/local.c
+++ b/local.c
@@ -416,6 +416,19 @@ clamp_freq(double freq)
 
 /* ================================================== */
 
+static int
+check_offset(struct timeval *now, double offset)
+{
+  /* Check if the time will be still sane with accumulated offset */
+  if (UTI_IsTimeOffsetSane(now, -offset))
+      return 1;
+
+  LOG(LOGS_WARN, LOGF_Local, "Adjustment of %.1f seconds is invalid", -offset);
+  return 0;
+}
+
+/* ================================================== */
+
 /* This involves both setting the absolute frequency with the
    system-specific driver, as well as calling all notify handlers */
 
@@ -490,6 +503,9 @@ LCL_AccumulateOffset(double offset, double corr_rate)
   LCL_ReadRawTime(&raw);
   LCL_CookTime(&raw, &cooked, NULL);
 
+  if (!check_offset(&cooked, offset))
+      return;
+
   (*drv_accrue_offset)(offset, corr_rate);
 
   /* Dispatch to all handlers */
@@ -498,7 +514,7 @@ LCL_AccumulateOffset(double offset, double corr_rate)
 
 /* ================================================== */
 
-void
+int
 LCL_ApplyStepOffset(double offset)
 {
   struct timeval raw, cooked;
@@ -509,6 +525,9 @@ LCL_ApplyStepOffset(double offset)
   LCL_ReadRawTime(&raw);
   LCL_CookTime(&raw, &cooked, NULL);
 
+  if (!check_offset(&raw, offset))
+      return 0;
+
   (*drv_apply_step_offset)(offset);
 
   /* Reset smoothing on all clock steps */
@@ -516,6 +535,8 @@ LCL_ApplyStepOffset(double offset)
 
   /* Dispatch to all handlers */
   invoke_parameter_change_handlers(&raw, &cooked, 0.0, offset, LCL_ChangeStep);
+
+  return 1;
 }
 
 /* ================================================== */
@@ -557,6 +578,9 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
      to the change we are about to make */
   LCL_CookTime(&raw, &cooked, NULL);
 
+  if (!check_offset(&cooked, doffset))
+      return;
+
   old_freq_ppm = current_freq_ppm;
 
   /* Work out new absolute frequency.  Note that absolute frequencies
@@ -629,9 +653,13 @@ LCL_MakeStep(void)
   LCL_ReadRawTime(&raw);
   LCL_GetOffsetCorrection(&raw, &correction, NULL);
 
+  if (!check_offset(&raw, -correction))
+      return 0;
+
   /* Cancel remaining slew and make the step */
   LCL_AccumulateOffset(correction, 0.0);
-  LCL_ApplyStepOffset(-correction);
+  if (!LCL_ApplyStepOffset(-correction))
+    return 0;
 
   LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.6f seconds", correction);
 
diff --git a/local.h b/local.h
index 412b386612a7bab4a609c25e6548366fa90e5a3d..0dfdd73a391bbf96b9cf04e36b8695cffeebd4d0 100644 (file)
--- a/local.h
+++ b/local.h
@@ -159,7 +159,7 @@ extern void LCL_AccumulateOffset(double offset, double corr_rate);
    the system clock is fast on true time, i.e. it needs to be stepped
    backwards. (Same convention as for AccumulateOffset routine). */
 
-extern void LCL_ApplyStepOffset(double offset);
+extern int LCL_ApplyStepOffset(double offset);
 
 /* Routine to invoke notify handlers on an unexpected time jump
    in system clock */
index a8492bc6c4e3d002005aa83d5bb874c58688ab55..d85b610f5e359bc64b29c4f755bb2765e2d7c107 100644 (file)
@@ -1051,8 +1051,8 @@ REF_SetReference(int stratum,
   maybe_log_offset(our_offset, raw_now.tv_sec);
 
   if (step_offset != 0.0) {
-    LCL_ApplyStepOffset(step_offset);
-    LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped by %.6f seconds", -step_offset);
+    if (LCL_ApplyStepOffset(step_offset))
+      LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped by %.6f seconds", -step_offset);
   }
 
   LCL_SetSyncStatus(are_we_synchronised, offset_sd, offset_sd + root_delay / 2.0 + root_dispersion);
diff --git a/rtc.c b/rtc.c
index 46a607331e4008e657732d5ac6701ac6f5cda99a..2d0f9cd3883d838c27b9699f05e4e9a743bcb4a6 100644 (file)
--- a/rtc.c
+++ b/rtc.c
@@ -93,9 +93,9 @@ fallback_time_init(void)
   LCL_ReadCookedTime(&now, NULL);
 
   if (now.tv_sec < buf.st_mtime) {
-    LCL_ApplyStepOffset(now.tv_sec - buf.st_mtime);
-    LOG(LOGS_INFO, LOGF_Rtc,
-        "System clock set from driftfile %s", drift_file);
+    if (LCL_ApplyStepOffset(now.tv_sec - buf.st_mtime))
+      LOG(LOGS_INFO, LOGF_Rtc, "System clock set from driftfile %s",
+          drift_file);
   }
 }
 
index ad0a844144572f132ecca1f87e9ea6f1af96e2e5..40befb35d19b924a4431cb65614cb818ee246b8e 100644 (file)
@@ -1043,9 +1043,9 @@ RTC_Linux_TimePreInit(void)
 
       /* Set system time only if the step is larger than 1 second */
       if (fabs(sys_offset) >= 1.0) {
-        LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
-            accumulated_error);
-        LCL_ApplyStepOffset(sys_offset);
+        if (LCL_ApplyStepOffset(sys_offset))
+          LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
+              accumulated_error);
       }
     } else {
       LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970");
diff --git a/util.c b/util.c
index 7797a3b9559d3aa53e0cbb346500d715a3aa4931..e400d96b30465b914123c1bc572ba0118551229a 100644 (file)
--- a/util.c
+++ b/util.c
@@ -606,6 +606,36 @@ UTI_Int64ToTimeval(NTP_int64 *src,
 
 /* ================================================== */
 
+/* Maximum offset between two sane times */
+#define MAX_OFFSET 4294967296.0
+
+int
+UTI_IsTimeOffsetSane(struct timeval *tv, double offset)
+{
+  double t;
+
+  /* Handle nan correctly here */
+  if (!(offset > -MAX_OFFSET && offset < MAX_OFFSET))
+    return 0;
+
+  UTI_TimevalToDouble(tv, &t);
+  t += offset;
+
+  /* Time before 1970 is not considered valid */
+  if (t < 0.0)
+    return 0;
+
+#ifdef HAVE_LONG_TIME_T
+  /* Check if it's in the interval to which NTP time is mapped */
+  if (t < (double)NTP_ERA_SPLIT || t > (double)(NTP_ERA_SPLIT + (1LL << 32)))
+    return 0;
+#endif
+
+  return 1;
+}
+
+/* ================================================== */
+
 void
 UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest)
 {
diff --git a/util.h b/util.h
index 81fdd7de78e71d736efa7240e54e5ac84b128712..5ab9413e1445a851f8036da0ca6cdd46bd714f11 100644 (file)
--- a/util.h
+++ b/util.h
@@ -104,6 +104,9 @@ extern void UTI_TimevalToInt64(struct timeval *src, NTP_int64 *dest, uint32_t fu
 
 extern void UTI_Int64ToTimeval(NTP_int64 *src, struct timeval *dest);
 
+/* Check if time + offset is sane */
+extern int UTI_IsTimeOffsetSane(struct timeval *tv, double offset);
+
 extern void UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest);
 extern void UTI_TimevalHostToNetwork(struct timeval *src, Timeval *dest);