From 44b4e6aed3822f3057a43ff77533cb9c287e7fc9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Sep 2012 13:49:35 -0700 Subject: [PATCH] 3.5-stable patches added patches: time-avoid-making-adjustments-if-we-haven-t-accumulated-anything.patch time-improve-sanity-checking-of-timekeeping-inputs.patch time-move-ktime_t-overflow-checking-into-timespec_valid_strict.patch --- queue-3.5/series | 3 + ...s-if-we-haven-t-accumulated-anything.patch | 43 +++++ ...anity-checking-of-timekeeping-inputs.patch | 163 ++++++++++++++++++ ...-checking-into-timespec_valid_strict.patch | 101 +++++++++++ 4 files changed, 310 insertions(+) create mode 100644 queue-3.5/time-avoid-making-adjustments-if-we-haven-t-accumulated-anything.patch create mode 100644 queue-3.5/time-improve-sanity-checking-of-timekeeping-inputs.patch create mode 100644 queue-3.5/time-move-ktime_t-overflow-checking-into-timespec_valid_strict.patch diff --git a/queue-3.5/series b/queue-3.5/series index 1be46961985..494a0d74344 100644 --- a/queue-3.5/series +++ b/queue-3.5/series @@ -227,3 +227,6 @@ rds-set-correct-msg_namelen.patch libata-prevent-interface-errors-with-seagate-freeagent-goflex.patch sched-fix-race-in-task_group.patch media-lirc_sir-make-device-registration-work.patch +time-improve-sanity-checking-of-timekeeping-inputs.patch +time-avoid-making-adjustments-if-we-haven-t-accumulated-anything.patch +time-move-ktime_t-overflow-checking-into-timespec_valid_strict.patch diff --git a/queue-3.5/time-avoid-making-adjustments-if-we-haven-t-accumulated-anything.patch b/queue-3.5/time-avoid-making-adjustments-if-we-haven-t-accumulated-anything.patch new file mode 100644 index 00000000000..df59ab45c3f --- /dev/null +++ b/queue-3.5/time-avoid-making-adjustments-if-we-haven-t-accumulated-anything.patch @@ -0,0 +1,43 @@ +From john.stultz@linaro.org Thu Sep 27 13:28:32 2012 +From: John Stultz +Date: Tue, 11 Sep 2012 14:56:20 -0400 +Subject: time: Avoid making adjustments if we haven't accumulated anything +To: stable@vger.kernel.org +Cc: John Stultz , Prarit Bhargava , Ingo Molnar , Thomas Gleixner +Message-ID: <1347389781-54602-3-git-send-email-john.stultz@linaro.org> + +From: John Stultz + +commit bf2ac312195155511a0f79325515cbb61929898a upstream. + +If update_wall_time() is called and the current offset isn't large +enough to accumulate, avoid re-calling timekeeping_adjust which may +change the clock freq and can cause 1ns inconsistencies with +CLOCK_REALTIME_COARSE/CLOCK_MONOTONIC_COARSE. + +Signed-off-by: John Stultz +Cc: Prarit Bhargava +Cc: Ingo Molnar +Cc: stable@vger.kernel.org +Link: http://lkml.kernel.org/r/1345595449-34965-5-git-send-email-john.stultz@linaro.org +Signed-off-by: Thomas Gleixner +Signed-off-by: John Stultz +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/time/timekeeping.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/kernel/time/timekeeping.c ++++ b/kernel/time/timekeeping.c +@@ -1055,6 +1055,10 @@ static void update_wall_time(void) + #else + offset = (clock->read(clock) - clock->cycle_last) & clock->mask; + #endif ++ /* Check if there's really nothing to do */ ++ if (offset < timekeeper.cycle_interval) ++ goto out; ++ + timekeeper.xtime_nsec = (s64)timekeeper.xtime.tv_nsec << + timekeeper.shift; + diff --git a/queue-3.5/time-improve-sanity-checking-of-timekeeping-inputs.patch b/queue-3.5/time-improve-sanity-checking-of-timekeeping-inputs.patch new file mode 100644 index 00000000000..78bc8229a61 --- /dev/null +++ b/queue-3.5/time-improve-sanity-checking-of-timekeeping-inputs.patch @@ -0,0 +1,163 @@ +From john.stultz@linaro.org Thu Sep 27 13:27:22 2012 +From: John Stultz +Date: Tue, 11 Sep 2012 14:56:19 -0400 +Subject: time: Improve sanity checking of timekeeping inputs +To: stable@vger.kernel.org +Cc: John Stultz , Peter Zijlstra , Prarit Bhargava , Zhouping Liu , Ingo Molnar , Thomas Gleixner +Message-ID: <1347389781-54602-2-git-send-email-john.stultz@linaro.org> + +From: John Stultz + +commit 4e8b14526ca7fb046a81c94002c1c43b6fdf0e9b upstream. + +Unexpected behavior could occur if the time is set to a value large +enough to overflow a 64bit ktime_t (which is something larger then the +year 2262). + +Also unexpected behavior could occur if large negative offsets are +injected via adjtimex. + +So this patch improves the sanity check timekeeping inputs by +improving the timespec_valid() check, and then makes better use of +timespec_valid() to make sure we don't set the time to an invalid +negative value or one that overflows ktime_t. + +Note: This does not protect from setting the time close to overflowing +ktime_t and then letting natural accumulation cause the overflow. + +Reported-by: CAI Qian +Reported-by: Sasha Levin +Signed-off-by: John Stultz +Cc: Peter Zijlstra +Cc: Prarit Bhargava +Cc: Zhouping Liu +Cc: Ingo Molnar +Link: http://lkml.kernel.org/r/1344454580-17031-1-git-send-email-john.stultz@linaro.org +Signed-off-by: Thomas Gleixner +Signed-off-by: John Stultz +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/ktime.h | 7 ------- + include/linux/time.h | 22 ++++++++++++++++++++-- + kernel/time/timekeeping.c | 26 ++++++++++++++++++++++++-- + 3 files changed, 44 insertions(+), 11 deletions(-) + +--- a/include/linux/ktime.h ++++ b/include/linux/ktime.h +@@ -58,13 +58,6 @@ union ktime { + + typedef union ktime ktime_t; /* Kill this */ + +-#define KTIME_MAX ((s64)~((u64)1 << 63)) +-#if (BITS_PER_LONG == 64) +-# define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC) +-#else +-# define KTIME_SEC_MAX LONG_MAX +-#endif +- + /* + * ktime_t definitions when using the 64-bit scalar representation: + */ +--- a/include/linux/time.h ++++ b/include/linux/time.h +@@ -107,11 +107,29 @@ static inline struct timespec timespec_s + return ts_delta; + } + ++#define KTIME_MAX ((s64)~((u64)1 << 63)) ++#if (BITS_PER_LONG == 64) ++# define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC) ++#else ++# define KTIME_SEC_MAX LONG_MAX ++#endif ++ + /* + * Returns true if the timespec is norm, false if denorm: + */ +-#define timespec_valid(ts) \ +- (((ts)->tv_sec >= 0) && (((unsigned long) (ts)->tv_nsec) < NSEC_PER_SEC)) ++static inline bool timespec_valid(const struct timespec *ts) ++{ ++ /* Dates before 1970 are bogus */ ++ if (ts->tv_sec < 0) ++ return false; ++ /* Can't have more nanoseconds then a second */ ++ if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) ++ return false; ++ /* Disallow values that could overflow ktime_t */ ++ if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX) ++ return false; ++ return true; ++} + + extern void read_persistent_clock(struct timespec *ts); + extern void read_boot_clock(struct timespec *ts); +--- a/kernel/time/timekeeping.c ++++ b/kernel/time/timekeeping.c +@@ -384,7 +384,7 @@ int do_settimeofday(const struct timespe + struct timespec ts_delta; + unsigned long flags; + +- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) ++ if (!timespec_valid(tv)) + return -EINVAL; + + write_seqlock_irqsave(&timekeeper.lock, flags); +@@ -418,6 +418,8 @@ EXPORT_SYMBOL(do_settimeofday); + int timekeeping_inject_offset(struct timespec *ts) + { + unsigned long flags; ++ struct timespec tmp; ++ int ret = 0; + + if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) + return -EINVAL; +@@ -426,10 +428,17 @@ int timekeeping_inject_offset(struct tim + + timekeeping_forward_now(); + ++ tmp = timespec_add(timekeeper.xtime, *ts); ++ if (!timespec_valid(&tmp)) { ++ ret = -EINVAL; ++ goto error; ++ } ++ + timekeeper.xtime = timespec_add(timekeeper.xtime, *ts); + timekeeper.wall_to_monotonic = + timespec_sub(timekeeper.wall_to_monotonic, *ts); + ++error: /* even if we error out, we forwarded the time, so call update */ + timekeeping_update(true); + + write_sequnlock_irqrestore(&timekeeper.lock, flags); +@@ -437,7 +446,7 @@ int timekeeping_inject_offset(struct tim + /* signal hrtimers about time change */ + clock_was_set(); + +- return 0; ++ return ret; + } + EXPORT_SYMBOL(timekeeping_inject_offset); + +@@ -597,7 +606,20 @@ void __init timekeeping_init(void) + struct timespec now, boot; + + read_persistent_clock(&now); ++ if (!timespec_valid(&now)) { ++ pr_warn("WARNING: Persistent clock returned invalid value!\n" ++ " Check your CMOS/BIOS settings.\n"); ++ now.tv_sec = 0; ++ now.tv_nsec = 0; ++ } ++ + read_boot_clock(&boot); ++ if (!timespec_valid(&boot)) { ++ pr_warn("WARNING: Boot clock returned invalid value!\n" ++ " Check your CMOS/BIOS settings.\n"); ++ boot.tv_sec = 0; ++ boot.tv_nsec = 0; ++ } + + seqlock_init(&timekeeper.lock); + diff --git a/queue-3.5/time-move-ktime_t-overflow-checking-into-timespec_valid_strict.patch b/queue-3.5/time-move-ktime_t-overflow-checking-into-timespec_valid_strict.patch new file mode 100644 index 00000000000..09789577e4d --- /dev/null +++ b/queue-3.5/time-move-ktime_t-overflow-checking-into-timespec_valid_strict.patch @@ -0,0 +1,101 @@ +From john.stultz@linaro.org Thu Sep 27 13:29:32 2012 +From: John Stultz +Date: Tue, 11 Sep 2012 14:56:21 -0400 +Subject: time: Move ktime_t overflow checking into timespec_valid_strict +To: stable@vger.kernel.org +Cc: John Stultz , Zhouping Liu , Ingo Molnar , Prarit Bhargava , Thomas Gleixner , Linus Torvalds +Message-ID: <1347389781-54602-4-git-send-email-john.stultz@linaro.org> + +From: John Stultz + +commit cee58483cf56e0ba355fdd97ff5e8925329aa936 upstream. + +Andreas Bombe reported that the added ktime_t overflow checking added to +timespec_valid in commit 4e8b14526ca7 ("time: Improve sanity checking of +timekeeping inputs") was causing problems with X.org because it caused +timeouts larger then KTIME_T to be invalid. + +Previously, these large timeouts would be clamped to KTIME_MAX and would +never expire, which is valid. + +This patch splits the ktime_t overflow checking into a new +timespec_valid_strict function, and converts the timekeeping codes +internal checking to use this more strict function. + +Reported-and-tested-by: Andreas Bombe +Cc: Zhouping Liu +Cc: Ingo Molnar +Cc: Prarit Bhargava +Cc: Thomas Gleixner +Signed-off-by: John Stultz +Signed-off-by: Linus Torvalds +Signed-off-by: John Stultz +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/time.h | 7 +++++++ + kernel/time/timekeeping.c | 10 +++++----- + 2 files changed, 12 insertions(+), 5 deletions(-) + +--- a/include/linux/time.h ++++ b/include/linux/time.h +@@ -125,6 +125,13 @@ static inline bool timespec_valid(const + /* Can't have more nanoseconds then a second */ + if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) + return false; ++ return true; ++} ++ ++static inline bool timespec_valid_strict(const struct timespec *ts) ++{ ++ if (!timespec_valid(ts)) ++ return false; + /* Disallow values that could overflow ktime_t */ + if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX) + return false; +--- a/kernel/time/timekeeping.c ++++ b/kernel/time/timekeeping.c +@@ -384,7 +384,7 @@ int do_settimeofday(const struct timespe + struct timespec ts_delta; + unsigned long flags; + +- if (!timespec_valid(tv)) ++ if (!timespec_valid_strict(tv)) + return -EINVAL; + + write_seqlock_irqsave(&timekeeper.lock, flags); +@@ -429,7 +429,7 @@ int timekeeping_inject_offset(struct tim + timekeeping_forward_now(); + + tmp = timespec_add(timekeeper.xtime, *ts); +- if (!timespec_valid(&tmp)) { ++ if (!timespec_valid_strict(&tmp)) { + ret = -EINVAL; + goto error; + } +@@ -606,7 +606,7 @@ void __init timekeeping_init(void) + struct timespec now, boot; + + read_persistent_clock(&now); +- if (!timespec_valid(&now)) { ++ if (!timespec_valid_strict(&now)) { + pr_warn("WARNING: Persistent clock returned invalid value!\n" + " Check your CMOS/BIOS settings.\n"); + now.tv_sec = 0; +@@ -614,7 +614,7 @@ void __init timekeeping_init(void) + } + + read_boot_clock(&boot); +- if (!timespec_valid(&boot)) { ++ if (!timespec_valid_strict(&boot)) { + pr_warn("WARNING: Boot clock returned invalid value!\n" + " Check your CMOS/BIOS settings.\n"); + boot.tv_sec = 0; +@@ -665,7 +665,7 @@ static void update_sleep_time(struct tim + */ + static void __timekeeping_inject_sleeptime(struct timespec *delta) + { +- if (!timespec_valid(delta)) { ++ if (!timespec_valid_strict(delta)) { + printk(KERN_WARNING "__timekeeping_inject_sleeptime: Invalid " + "sleep delta value!\n"); + return; -- 2.47.2