forked from pool/util-linux
c56100b554
squashed sr234195 and re-submitted - Prevent excessive clock drift calculations (bnc#871698, util-linux-prevent-excessive-clock-drift-calculations.patch), committed by sbrabec@suse.cz OBS-URL: https://build.opensuse.org/request/show/234334 OBS-URL: https://build.opensuse.org/package/show/Base:System/util-linux?expand=0&rev=240
163 lines
5.1 KiB
Diff
163 lines
5.1 KiB
Diff
From 654e902731ea15a3494a3831b78d2b9f1cd1408d Mon Sep 17 00:00:00 2001
|
|
From: Ruediger Meier <ruediger.meier@ga-group.nl>
|
|
Date: Fri, 16 May 2014 17:01:43 +0200
|
|
Subject: [PATCH] Prevent excessive clock drift calculations
|
|
|
|
Squashed commit of the following:
|
|
|
|
commit f55b4b45126b657fe02f5f0d3d7fde740e6a6247
|
|
Author: Karel Zak <kzak@redhat.com>
|
|
Date: Tue May 6 12:51:42 2014 +0200
|
|
|
|
hwclock: fix typo
|
|
|
|
Reported-by: Stanislav Brabec <sbrabec@suse.cz>
|
|
Signed-off-by: Karel Zak <kzak@redhat.com>
|
|
|
|
commit db8fc5f37728810bdd5b865ac420c31714e35def
|
|
Author: Stanislav Brabec <sbrabec@suse.cz>
|
|
Date: Mon May 5 20:49:49 2014 +0200
|
|
|
|
hwclock: Check drift value in /etc/adjtime
|
|
|
|
Due to bug in older versions of hwclock, /etc/adjtime can contain
|
|
excessive drift value (up to many years per day). Prevent it
|
|
from applying.
|
|
|
|
Signed-off-by: Stanislav Brabec <sbrabec@suse.cz>
|
|
|
|
commit f196fd1a5f8fff63635fd88b5a0f0bbc96978df2
|
|
Author: Stanislav Brabec <sbrabec@suse.cz>
|
|
Date: Mon May 5 20:49:29 2014 +0200
|
|
|
|
hwclock: Prevent excessive drift values
|
|
|
|
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@suse.cz>
|
|
|
|
Signed-off-by: Ruediger Meier <ruediger.meier@ga-group.nl>
|
|
---
|
|
sys-utils/hwclock.c | 47 ++++++++++++++++++++++++++++++++++-------------
|
|
1 file changed, 34 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c
|
|
index 395b5c3..0abf01f 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;
|
|
|
|
@@ -1190,9 +1208,12 @@ do_adjustment(struct adjtime *adjtime_p,
|
|
adjtime_p->dirty = TRUE;
|
|
} else if (adjtime_p->last_adj_time == 0) {
|
|
if (debug)
|
|
- printf(_
|
|
- ("Not setting clock because last adjustment time is zero, "
|
|
- "so history is bad."));
|
|
+ printf(_("Not setting clock because last adjustment time is zero, "
|
|
+ "so history is bad.\n"));
|
|
+ } else if (abs(adjtime_p->drift_factor) > MAX_DRIFT) {
|
|
+ if (debug)
|
|
+ printf(_("Not setting clock because drift factor %f is far too high.\n"),
|
|
+ adjtime_p->drift_factor);
|
|
} else {
|
|
int adjustment;
|
|
/* Number of seconds we must insert in the Hardware Clock */
|
|
--
|
|
1.8.4.5
|
|
|