[PATCH 1/2] hwclock: Prevent excessive drift values

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Failure of CMOS battery can cause writing of excessive drift
values (up to many years per day).

This causes excessive hwclock adjustment next time, which may lead
to overflow in calculate_adjustment() (and hang before 4a44a54b).

Prevent this situation, check drift for limits and reset drift to zero
instead.

Steps to reproduce:

mv /etc/adjtime /etc/adjtime.backup

rm /etc/adjtime
hwclock --set --date 2001-01-01\ 01:00:00

changing of /etc/adjtime.
mv /etc/adjtime /etc/adjtime.saved
hwclock --set --date 2001-01-02\ 01:00:01
mv /etc/adjtime.saved /etc/adjtime

echo "======= The /etc/adjtime has a \"correct\" look:"
cat /etc/adjtime

hwclock --debug --systohc --utc
echo "======= The /etc/adjtime now has deeply failed drift value:"
cat /etc/adjtime

mv /etc/adjtime /etc/adjtime.saved
hwclock --set --date 2015-01-01\ 01:00:00
mv /etc/adjtime.saved /etc/adjtime

hwclock --debug --adjust
echo "======= And the last /etc/adjtime:"
cat /etc/adjtime

mv /etc/adjtime.backup /etc/adjtime
hwclock --systohc --utc

Signed-off-by: Stanislav Brabec <sbrabec@xxxxxxx>
---
 sys-utils/hwclock.c | 38 ++++++++++++++++++++++++++++----------
 1 file changed, 28 insertions(+), 10 deletions(-)

diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c
index 395b5c3..5e786a8 100644
--- a/sys-utils/hwclock.c
+++ b/sys-utils/hwclock.c
@@ -91,6 +91,11 @@ struct clock_ops *ur;
 
 #define FLOOR(arg) ((arg >= 0 ? (int) arg : ((int) arg) - 1));
 
+/* Maximal clock adjustment in seconds per day.
+   (adjtime() glibc call has 2145 seconds limit on i386, so it is good enough for us as well,
+   43219 is a maximal safe value preventing exact_adjustment overflow.) */
+#define MAX_DRIFT 2145.0
+
 const char *adj_file_name = NULL;
 
 struct adjtime {
@@ -1008,6 +1013,7 @@ adjust_drift_factor(struct adjtime *adjtime_p,
 		double adj_days, cal_days;
 		double exp_drift, unc_drift;
 		double factor_adjust;
+		double drift_factor;
 
 		/* Adjusted time units per hardware time unit */
 		atime_per_htime = 1.0 + adjtime_p->drift_factor / sec_per_day;
@@ -1033,16 +1039,28 @@ adjust_drift_factor(struct adjtime *adjtime_p,
 		/* Amount to add to previous drift factor */
 		factor_adjust = unc_drift / cal_days;
 
-		if (debug)
-			printf(_("Clock drifted %.1f seconds in the past "
-				 "%d seconds in spite of a drift factor of "
-				 "%f seconds/day.\n"
-				 "Adjusting drift factor by %f seconds/day\n"),
-			       unc_drift,
-			       (int)(nowtime - adjtime_p->last_calib_time),
-			       adjtime_p->drift_factor, factor_adjust);
-
-		adjtime_p->drift_factor += factor_adjust;
+		/* New drift factor */
+		drift_factor = adjtime_p->drift_factor + factor_adjust;
+
+		if (abs(drift_factor) > MAX_DRIFT) {
+			if (debug)
+				printf(_("Clock drift factor was calculated as "
+					 "%f seconds/day.\n"
+					 "It is far too much. Resetting to zero.\n"),
+				       drift_factor);
+			drift_factor = 0;
+		} else {
+			if (debug)
+				printf(_("Clock drifted %.1f seconds in the past "
+					 "%d seconds in spite of a drift factor of "
+					 "%f seconds/day.\n"
+					 "Adjusting drift factor by %f seconds/day\n"),
+				       unc_drift,
+				       (int)(nowtime - adjtime_p->last_calib_time),
+				       adjtime_p->drift_factor, factor_adjust);
+		}
+
+		adjtime_p->drift_factor = drift_factor;
 	}
 	adjtime_p->last_calib_time = nowtime;
 
-- 
1.8.4.5

-- 
Best Regards / S pozdravem,

Stanislav Brabec
software developer
---------------------------------------------------------------------
SUSE LINUX, s. r. o.                          e-mail: sbrabec@xxxxxxx
Lihovarská 1060/12                            tel: +49 911 7405384547
190 00 Praha 9                                 fax:  +420 284 084 001
Czech Republic                                    http://www.suse.cz/
PGP: 830B 40D5 9E05 35D8 5E27 6FA3 717C 209F A04F CD76

--
To unsubscribe from this list: send the line "unsubscribe util-linux" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux