local: check offset sanity before accumulation

Don't accept an offset that points to time before 1970 or outside the
interval to which is mapped NTP time.
This commit is contained in:
Miroslav Lichvar 2015-04-07 14:58:58 +02:00
parent 183a648d01
commit aec97397e8
8 changed files with 77 additions and 13 deletions

View file

@ -1555,8 +1555,11 @@ handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message)
static void static void
handle_make_step(CMD_Request *rx_message, CMD_Reply *tx_message) handle_make_step(CMD_Request *rx_message, CMD_Reply *tx_message)
{ {
LCL_MakeStep(); if (!LCL_MakeStep()) {
tx_message->status = htons(STT_FAILED);
} else {
tx_message->status = htons(STT_SUCCESS); tx_message->status = htons(STT_SUCCESS);
}
} }
/* ================================================== */ /* ================================================== */

32
local.c
View file

@ -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 /* This involves both setting the absolute frequency with the
system-specific driver, as well as calling all notify handlers */ 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_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL); LCL_CookTime(&raw, &cooked, NULL);
if (!check_offset(&cooked, offset))
return;
(*drv_accrue_offset)(offset, corr_rate); (*drv_accrue_offset)(offset, corr_rate);
/* Dispatch to all handlers */ /* Dispatch to all handlers */
@ -498,7 +514,7 @@ LCL_AccumulateOffset(double offset, double corr_rate)
/* ================================================== */ /* ================================================== */
void int
LCL_ApplyStepOffset(double offset) LCL_ApplyStepOffset(double offset)
{ {
struct timeval raw, cooked; struct timeval raw, cooked;
@ -509,6 +525,9 @@ LCL_ApplyStepOffset(double offset)
LCL_ReadRawTime(&raw); LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL); LCL_CookTime(&raw, &cooked, NULL);
if (!check_offset(&raw, offset))
return 0;
(*drv_apply_step_offset)(offset); (*drv_apply_step_offset)(offset);
/* Reset smoothing on all clock steps */ /* Reset smoothing on all clock steps */
@ -516,6 +535,8 @@ LCL_ApplyStepOffset(double offset)
/* Dispatch to all handlers */ /* Dispatch to all handlers */
invoke_parameter_change_handlers(&raw, &cooked, 0.0, offset, LCL_ChangeStep); 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 */ to the change we are about to make */
LCL_CookTime(&raw, &cooked, NULL); LCL_CookTime(&raw, &cooked, NULL);
if (!check_offset(&cooked, doffset))
return;
old_freq_ppm = current_freq_ppm; old_freq_ppm = current_freq_ppm;
/* Work out new absolute frequency. Note that absolute frequencies /* Work out new absolute frequency. Note that absolute frequencies
@ -629,9 +653,13 @@ LCL_MakeStep(void)
LCL_ReadRawTime(&raw); LCL_ReadRawTime(&raw);
LCL_GetOffsetCorrection(&raw, &correction, NULL); LCL_GetOffsetCorrection(&raw, &correction, NULL);
if (!check_offset(&raw, -correction))
return 0;
/* Cancel remaining slew and make the step */ /* Cancel remaining slew and make the step */
LCL_AccumulateOffset(correction, 0.0); 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); LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.6f seconds", correction);

View file

@ -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 the system clock is fast on true time, i.e. it needs to be stepped
backwards. (Same convention as for AccumulateOffset routine). */ 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 /* Routine to invoke notify handlers on an unexpected time jump
in system clock */ in system clock */

View file

@ -1051,7 +1051,7 @@ REF_SetReference(int stratum,
maybe_log_offset(our_offset, raw_now.tv_sec); maybe_log_offset(our_offset, raw_now.tv_sec);
if (step_offset != 0.0) { if (step_offset != 0.0) {
LCL_ApplyStepOffset(step_offset); if (LCL_ApplyStepOffset(step_offset))
LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped by %.6f seconds", -step_offset); LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped by %.6f seconds", -step_offset);
} }

6
rtc.c
View file

@ -93,9 +93,9 @@ fallback_time_init(void)
LCL_ReadCookedTime(&now, NULL); LCL_ReadCookedTime(&now, NULL);
if (now.tv_sec < buf.st_mtime) { if (now.tv_sec < buf.st_mtime) {
LCL_ApplyStepOffset(now.tv_sec - buf.st_mtime); if (LCL_ApplyStepOffset(now.tv_sec - buf.st_mtime))
LOG(LOGS_INFO, LOGF_Rtc, LOG(LOGS_INFO, LOGF_Rtc, "System clock set from driftfile %s",
"System clock set from driftfile %s", drift_file); drift_file);
} }
} }

View file

@ -1043,9 +1043,9 @@ RTC_Linux_TimePreInit(void)
/* Set system time only if the step is larger than 1 second */ /* Set system time only if the step is larger than 1 second */
if (fabs(sys_offset) >= 1.0) { if (fabs(sys_offset) >= 1.0) {
if (LCL_ApplyStepOffset(sys_offset))
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f", LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
accumulated_error); accumulated_error);
LCL_ApplyStepOffset(sys_offset);
} }
} else { } else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970"); LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970");

30
util.c
View file

@ -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 void
UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest) UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest)
{ {

3
util.h
View file

@ -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); 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_TimevalNetworkToHost(Timeval *src, struct timeval *dest);
extern void UTI_TimevalHostToNetwork(struct timeval *src, Timeval *dest); extern void UTI_TimevalHostToNetwork(struct timeval *src, Timeval *dest);