All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] ntp: Verify offset doesn't overflow in ntp_update_offset
@ 2015-12-10 19:51 John Stultz
  2015-12-10 19:51 ` [PATCH v3] time: Verify time values in adjtimex ADJ_SETOFFSET to avoid overflow John Stultz
  0 siblings, 1 reply; 2+ messages in thread
From: John Stultz @ 2015-12-10 19:51 UTC (permalink / raw)
  To: lkml; +Cc: Sasha Levin, Richard Cochran, Thomas Gleixner, John Stultz

From: Sasha Levin <sasha.levin@oracle.com>

We need to make sure that the offset is valid before manipulating it,
otherwise it might overflow on the multiplication.

Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
[jstultz: Reworked one of the checks so it makes more sense]
Signed-off-by: John Stultz <john.stultz@linaro.org>
---
v2: Reworked the overflow clamp to make more sense.

 kernel/time/ntp.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 149cc80..125fc03 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -297,15 +297,17 @@ static void ntp_update_offset(long offset)
 	if (!(time_status & STA_PLL))
 		return;
 
-	if (!(time_status & STA_NANO))
+	if (!(time_status & STA_NANO)) {
+		/* Make sure the multiplication below won't overflow */
+		offset = clamp(offset, -USEC_PER_SEC, USEC_PER_SEC);
 		offset *= NSEC_PER_USEC;
+	}
 
 	/*
 	 * Scale the phase adjustment and
 	 * clamp to the operating range.
 	 */
-	offset = min(offset, MAXPHASE);
-	offset = max(offset, -MAXPHASE);
+	offset = clamp(offset, -MAXPHASE, MAXPHASE);
 
 	/*
 	 * Select how the frequency is to be controlled
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [PATCH v3] time: Verify time values in adjtimex ADJ_SETOFFSET to avoid overflow
  2015-12-10 19:51 [PATCH v2] ntp: Verify offset doesn't overflow in ntp_update_offset John Stultz
@ 2015-12-10 19:51 ` John Stultz
  0 siblings, 0 replies; 2+ messages in thread
From: John Stultz @ 2015-12-10 19:51 UTC (permalink / raw)
  To: lkml; +Cc: John Stultz, Sasha Levin, Richard Cochran, Thomas Gleixner

For adjtimex()'s ADJ_SETOFFSET, make sure the tv_usec value is
sane. We might multiply them later which can cause an overflow
and undefined behavior.

This patch introduces new helper functions to simplify the
checking code and adds comments to clarify

Orginally this patch was by Sasha Levin, but I've basically
rewritten it, so he should get credit for finding the issue
and I should get the blame for any mistakes made since.

Also, credit to Richard Cochran for the phrasing used in the
comment for what is considered valid here.

Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Reported-by: Sasha Levin <sasha.levin@oracle.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>
---
v3:
 * Reworked to use helper functions, per tglx's request.
 * Re-attributed authorship, since its been totally redone.

 include/linux/time.h      | 26 ++++++++++++++++++++++++++
 kernel/time/ntp.c         | 10 ++++++++--
 kernel/time/timekeeping.c |  2 +-
 3 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/include/linux/time.h b/include/linux/time.h
index beebe3a..297f09f 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -125,6 +125,32 @@ static inline bool timeval_valid(const struct timeval *tv)
 
 extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
 
+/*
+ * Validates if a timespec/timeval used to inject a time offset is valid.
+ * Offsets can be postive or negative. The value of the timeval/timespec
+ * is the sum of its fields, but *NOTE*: the field tv_usec/tv_nsec must
+ * always be non-negative.
+ */
+static inline bool timeval_inject_offset_valid(const struct timeval *tv)
+{
+	/* We don't check the tv_sec as it can be positive or negative */
+
+	/* Can't have more microseconds then a second */
+	if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC)
+		return false;
+	return true;
+}
+
+static inline bool timespec_inject_offset_valid(const struct timespec *ts)
+{
+	/* We don't check the tv_sec as it can be positive or negative */
+
+	/* Can't have more nanoseconds then a second */
+	if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC)
+		return false;
+	return true;
+}
+
 #define CURRENT_TIME		(current_kernel_time())
 #define CURRENT_TIME_SEC	((struct timespec) { get_seconds(), 0 })
 
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 125fc03..4073c95 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -676,8 +676,14 @@ int ntp_validate_timex(struct timex *txc)
 			return -EINVAL;
 	}
 
-	if ((txc->modes & ADJ_SETOFFSET) && (!capable(CAP_SYS_TIME)))
-		return -EPERM;
+	if (txc->modes & ADJ_SETOFFSET) {
+		/* In order to inject time, you gotta be super-user! */
+		if (!capable(CAP_SYS_TIME))
+			return -EPERM;
+
+		if (!timeval_inject_offset_valid(&txc->time))
+			return -EINVAL;
+	}
 
 	/*
 	 * Check for potential multiplication overflows that can
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 99188ee..d9249da 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -958,7 +958,7 @@ int timekeeping_inject_offset(struct timespec *ts)
 	struct timespec64 ts64, tmp;
 	int ret = 0;
 
-	if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
+	if (!timespec_inject_offset_valid(ts))
 		return -EINVAL;
 
 	ts64 = timespec_to_timespec64(*ts);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2015-12-10 19:51 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-10 19:51 [PATCH v2] ntp: Verify offset doesn't overflow in ntp_update_offset John Stultz
2015-12-10 19:51 ` [PATCH v3] time: Verify time values in adjtimex ADJ_SETOFFSET to avoid overflow John Stultz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.