3
0
forked from pool/util-linux
util-linux/util-linux-prevent-excessive-clock-drift-calculations.patch
Ruediger Meier c56100b554 Accepting request 234334 from home:rudi_m:branches:uuu
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
2014-05-20 18:42:15 +00:00

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