From f7daec0693aee108866134a08c6f881c18502156 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Thu, 3 Apr 2025 15:50:29 +0200 Subject: [PATCH] sys_timex: detect clock interference from other processes 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 | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sys_timex.c b/sys_timex.c index 0ee6c8ef..2cabb888 100644 --- a/sys_timex.c +++ b/sys_timex.c @@ -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; } -- 2.47.3