]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
sys_timex: detect clock interference from other processes
authorMiroslav Lichvar <mlichvar@redhat.com>
Thu, 3 Apr 2025 13:50:29 +0000 (15:50 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Thu, 3 Apr 2025 14:27:26 +0000 (16:27 +0200)
After an ntp_adjtime()/adjtimex() call, check if the frequency, PLL time
constant and PLL status are as expected from the previous call. If they
changed, log a warning message to indicate that another NTP client might
be running on the system and interfering with the system clock.

sys_timex.c

index 0ee6c8ef02a4fc06418f51946ca5ebf2843499d0..2cabb8888c9ffe03723315ed5890ff6cb9d1c0c2 100644 (file)
@@ -257,6 +257,8 @@ SYS_Timex_Finalise(void)
 int
 SYS_Timex_Adjust(struct timex *txc, int ignore_error)
 {
+  static long last_constant, last_freq;
+  static int last_status = -1;
   int state;
 
 #ifdef SOLARIS
@@ -270,7 +272,24 @@ SYS_Timex_Adjust(struct timex *txc, int ignore_error)
   if (state < 0) {
     LOG(ignore_error ? LOGS_DEBUG : LOGS_FATAL,
         NTP_ADJTIME_NAME"(0x%x) failed : %s", txc->modes, strerror(errno));
+    return state;
   }
 
+  /* This a good place to verify that nothing else is touching the clock,
+     without making an additional timex call.  A clock update is normally
+     expected to have four driver calls:
+     - set_sync_status - primarily updating leap status
+     - set_frequency - correcting frequency error
+     - set_frequency - correcting phase error
+     - set_sync_status - updating leap and estimated/maximum error */
+  if (last_status != -1 &&
+      (((last_status ^ txc->status) & STA_PLL && !(txc->modes & MOD_STATUS)) ||
+       (last_constant != txc->constant && !(txc->modes & MOD_TIMECONST)) ||
+       (last_freq != txc->freq && !(txc->modes & MOD_FREQUENCY))))
+    LOG(LOGS_WARN, "System clock interference detected (another NTP client?)");
+  last_status = txc->status;
+  last_constant = txc->constant;
+  last_freq = txc->freq;
+
   return state;
 }