[Git][NTPsec/ntpsec][master] Restore cross-era interoperability via pivoting timestamps on build data.

Eric S. Raymond gitlab at mg.gitlab.com
Mon Apr 17 16:22:14 UTC 2017


Eric S. Raymond pushed to branch master at NTPsec / ntpsec


Commits:
c0973bb2 by Eric S. Raymond at 2017-04-17T12:15:02-04:00
Restore cross-era interoperability via pivoting timestamps on build data.

This repairs an error first introduced some weeks ago during an l_fp cleanup
pass and compounded by later changes. It was insidious because the effects
would not have shown until 2036, at which point interoperability between
ntpd instances built before and after the era 1 epoch would have broken.

- - - - -


3 changed files:

- include/ntp_calendar.h
- libntp/ntp_calendar.c
- libntp/systime.c


Changes:

=====================================
include/ntp_calendar.h
=====================================
--- a/include/ntp_calendar.h
+++ b/include/ntp_calendar.h
@@ -195,23 +195,23 @@ ntpcal_daysec_to_date(struct calendar * /* jt */, int32_t /* secs */);
 extern int32_t
 ntpcal_date_to_daysec(const struct calendar *);
 
-/* used by ntpd/refclock_gpsd.c */
-extern int32_t
-ntpcal_tm_to_daysec(const struct tm * /* utm */);
-
-
 /*
- * convert a RataDie to the RataDie of start of the calendar month.
+ * Take a value of seconds since midnight and split it into hhmmss in
+ * a 'struct tm'. Return excessive days.
  */
 extern int32_t
-ntpcal_rd_to_mstart(int32_t /* year */);
+ntpcal_daysec_to_tm(struct tm * /* utm */, int32_t /* secs */);
 
+extern int32_t
+ntpcal_tm_to_daysec(const struct tm * /* utm */);
 
+extern int
+ntpcal_daysplit_to_date(struct calendar * /* jt */,
+			const ntpcal_split * /* ds */, int32_t /* dof */);
 
 extern int
 ntpcal_time_to_date(struct calendar * /* jd */, const time64_t /* ts */);
 
-/* used by ntpd/refclock_nmea.c */
 extern int32_t
 ntpcal_periodic_extend(int32_t /* pivot */, int32_t /* value */,
 		       int32_t /* cycle */) __attribute__((const));
@@ -219,11 +219,12 @@ ntpcal_periodic_extend(int32_t /* pivot */, int32_t /* value */,
 extern int
 ntpcal_ntp64_to_date(struct calendar * /* jd */, const time64_t /* ntp */);
 
-/* used by ntpd/refclock_nmea.c */
 extern int
 ntpcal_ntp_to_date(struct calendar * /* jd */,	uint32_t /* ntp */,
 		   const time_t * /* pivot */);
 
+extern time_t
+ntpcal_date_to_time(const struct calendar * /* jd */);
 
 
 /*


=====================================
libntp/ntp_calendar.c
=====================================
--- a/libntp/ntp_calendar.c
+++ b/libntp/ntp_calendar.c
@@ -582,7 +582,6 @@ ntpcal_rd_to_date(
 	return retv ? retv : leaps;
 }
 
-
 /*
  *---------------------------------------------------------------------
  * Take a value of seconds since midnight and split it into hhmmss in a
@@ -606,7 +605,49 @@ ntpcal_daysec_to_date(
 	return days;
 }
 
+/*
+ *---------------------------------------------------------------------
+ * Take a value of seconds since midnight and split it into hhmmss in a
+ * 'struct tm'.
+ *---------------------------------------------------------------------
+ */
+int32_t
+ntpcal_daysec_to_tm(
+	struct tm *utm,
+	int32_t	   sec
+	)
+{
+	int32_t days;
+	int32_t ts[3];
+
+	days = priv_timesplit(ts, sec);
+	utm->tm_hour = ts[0];
+	utm->tm_min  = ts[1];
+	utm->tm_sec  = ts[2];
+
+	return days;
+}
 
+/*
+ *---------------------------------------------------------------------
+ * take a split representation for day/second-of-day and day offset
+ * and convert it to a 'struct calendar'. The seconds will be normalised
+ * into the range of a day, and the day will be adjusted accordingly.
+ *
+ * returns >0 if the result is in a leap year, 0 if in a regular
+ * year and <0 if the result did not fit into the calendar struct.
+ *---------------------------------------------------------------------
+ */
+int
+ntpcal_daysplit_to_date(
+	struct calendar	   *jd,
+	const ntpcal_split *ds,
+	int32_t		    dof
+	)
+{
+	dof += ntpcal_daysec_to_date(jd, ds->lo);
+	return ntpcal_rd_to_date(jd, ds->hi + dof);
+}
 
 /*
  *---------------------------------------------------------------------
@@ -863,25 +904,6 @@ ntpcal_date_to_rd(
 
 /*
  *---------------------------------------------------------------------
- * For a given RD, get the RD of the associated month start.
- *---------------------------------------------------------------------
- */
-int32_t
-ntpcal_rd_to_mstart(
-	int32_t rd
-	)
-{
-	ntpcal_split split;
-	int32_t	     leaps;
-
-	split = ntpcal_split_eradays(rd - 1, &leaps);
-	split = ntpcal_split_yeardays(split.lo, leaps);
-
-	return rd - split.lo;
-}
-
-/*
- *---------------------------------------------------------------------
  * take a 'struct calendar' and get the seconds-of-day from it.
  *---------------------------------------------------------------------
  */
@@ -908,6 +930,27 @@ ntpcal_tm_to_daysec(
 				       utm->tm_sec);
 }
 
+/*
+ *---------------------------------------------------------------------
+ * take a 'struct calendar' and convert it to a 'time_t'
+ *---------------------------------------------------------------------
+ */
+time_t
+ntpcal_date_to_time(
+	const struct calendar *jd
+	)
+{
+	time64_t  join;
+	int32_t days, secs;
+
+	days = ntpcal_date_to_rd(jd) - DAY_UNIX_STARTS;
+	secs = ntpcal_date_to_daysec(jd);
+	join = ntpcal_dayjoin(days, secs);
+
+	/* might truncate if time_t is 32 bits */
+	return (time_t)join;
+}
+
 
 int
 ntpcal_ntp64_to_date(
@@ -941,5 +984,4 @@ ntpcal_ntp_to_date(
 	return ntpcal_ntp64_to_date(jd, ntp64);
 }
 
-
 /* -*-EOF-*- */


=====================================
libntp/systime.c
=====================================
--- a/libntp/systime.c
+++ b/libntp/systime.c
@@ -317,22 +317,71 @@ step_systime(
 	int (*settime)(struct timespec *)
 	)
 {
+	time_t pivot; /* for ntp era unfolding */
 	struct timespec timets, tslast, tsdiff;
-	struct timespec ofs_ts; /* desired offset as teimspec */
+	struct calendar jd;
+	l_fp fp_ofs, fp_sys; /* offset and target system time in FP */
 
-	/* get the complete jump distance as timespec */
-        ofs_ts = d_to_tspec(step + sys_residual);
+	/*
+	 * Get pivot time for NTP era unfolding. Since we don't step
+	 * very often, we can afford to do the whole calculation from
+	 * scratch. And we're not in the time-critical path yet.
+	 */
+#if NTP_SIZEOF_TIME_T > 4
+	/*
+	 * This code makes sure the resulting time stamp for the new
+	 * system time is in the 2^32 seconds starting at 1970-01-01,
+	 * 00:00:00 UTC.
+	 */
+	pivot = 0x80000000;
+#if USE_COMPILETIME_PIVOT
+	/*
+	 * Add the compile time minus 10 years to get a possible target
+	 * area of (compile time - 10 years) to (compile time + 126
+	 * years).  This should be sufficient for a given binary of
+	 * NTPD.
+	 */
+	if (ntpcal_get_build_date(&jd)) {
+		jd.year -= 10;
+		pivot += ntpcal_date_to_time(&jd);
+	} else {
+		msyslog(LOG_ERR,
+			"step_systime: assume 1970-01-01 as build date");
+	}
+#else
+	UNUSED_LOCAL(jd);
+#endif /* USE_COMPILETIME_PIVOT */
+#else
+	UNUSED_LOCAL(jd);
+	/* This makes sure the resulting time stamp is on or after
+	 * 1969-12-31/23:59:59 UTC and gives us additional two years,
+	 * from the change of NTP era in 2036 to the UNIX rollover in
+	 * 2038. (Minus one second, but that won't hurt.) We *really*
+	 * need a longer 'time_t' after that!  Or a different baseline,
+	 * but that would cause other serious trouble, too.
+	 */
+	pivot = 0x7FFFFFFF;
+#endif
+
+	/* get the complete jump distance as l_fp */
+	fp_sys = dtolfp(sys_residual);
+	fp_ofs = dtolfp(step);
+	fp_ofs += fp_sys;
 
 	/* ---> time-critical path starts ---> */
 
-	/* get the current time as, without fuzz, as struct timespec */
+	/* get the current time as l_fp (without fuzz) and as struct timespec */
 	get_ostime(&timets);
+	fp_sys = tspec_stamp_to_lfp(timets);
+
+	/* get the target time as l_fp */
+	fp_sys += fp_ofs;
 
-	/* add offset */
-	tslast = add_tspec(timets, ofs_ts);
+	/* unfold the new system time */
+	timets = lfp_stamp_to_tspec(fp_sys, &pivot);
 
 	/* now set new system time */
-	if (settime(&tslast) != 0) {
+	if (settime(&timets) != 0) {
 		msyslog(LOG_ERR, "step_systime: %m");
 		return false;
 	}
@@ -340,6 +389,8 @@ step_systime(
 	/* <--- time-critical path ended with call to the settime hook <--- */
 
 	/* only used for utmp/wtmpx time-step recording */
+	tslast.tv_sec = timets.tv_sec;
+	tslast.tv_nsec = timets.tv_nsec;
 
 	sys_residual = 0;
 	lamport_violated = (step < 0);



View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/c0973bb27e231356290bb51964175da4a404ca4e

---
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/c0973bb27e231356290bb51964175da4a404ca4e
You're receiving this email because of your account on gitlab.com.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ntpsec.org/pipermail/vc/attachments/20170417/a6ad901c/attachment.html>


More information about the vc mailing list