]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.5-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 31 Aug 2012 18:02:26 +0000 (11:02 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 31 Aug 2012 18:02:26 +0000 (11:02 -0700)
added patches:
time-improve-sanity-checking-of-timekeeping-inputs.patch

queue-3.5/series
queue-3.5/time-improve-sanity-checking-of-timekeeping-inputs.patch [new file with mode: 0644]

index fdbcedba735b21c598faf70d1397e0f5e124972c..0afb1d000e7a011f433701c78994d401df9de6f2 100644 (file)
@@ -60,3 +60,4 @@ alsa-usb-audio-fix-scheduling-while-atomic-bug-in-pcm-capture-stream.patch
 sched-cgroup-fix-up-task_groups-list.patch
 sched-fix-divide-by-zero-at-thread_group-task-_times.patch
 uvcvideo-reset-the-bytesused-field-when-recycling-an-erroneous-buffer.patch
+time-improve-sanity-checking-of-timekeeping-inputs.patch
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 (file)
index 0000000..1f6feb4
--- /dev/null
@@ -0,0 +1,160 @@
+From 4e8b14526ca7fb046a81c94002c1c43b6fdf0e9b Mon Sep 17 00:00:00 2001
+From: John Stultz <john.stultz@linaro.org>
+Date: Wed, 8 Aug 2012 15:36:20 -0400
+Subject: time: Improve sanity checking of timekeeping inputs
+
+From: John Stultz <john.stultz@linaro.org>
+
+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 <caiqian@redhat.com>
+Reported-by: Sasha Levin <levinsasha928@gmail.com>
+Signed-off-by: John Stultz <john.stultz@linaro.org>
+Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Cc: Prarit Bhargava <prarit@redhat.com>
+Cc: Zhouping Liu <zliu@redhat.com>
+Cc: Ingo Molnar <mingo@kernel.org>
+Link: http://lkml.kernel.org/r/1344454580-17031-1-git-send-email-john.stultz@linaro.org
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/linux/ktime.h     |    7 -------
+ include/linux/time.h      |   22 ++++++++++++++++++++--
+ kernel/time/timekeeping.c |   27 +++++++++++++++++++++++++--
+ 3 files changed, 45 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,18 @@ int timekeeping_inject_offset(struct tim
+       timekeeping_forward_now();
++      /* Make sure the proposed value is valid */
++      tmp = timespec_add(tk_xtime(tk),  *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 +447,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 +607,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);