Commit 5f4d5404ee8af904b8e843a7fc21f27ff8e6cb83

Authored by Sasha Levin
Committed by Greg Kroah-Hartman
1 parent cfaa6851b0

time: settimeofday: Validate the values of tv from user

commit 6ada1fc0e1c4775de0e043e1bd3ae9d065491aa5 upstream.

An unvalidated user input is multiplied by a constant, which can result in
an undefined behaviour for large values. While this is validated later,
we should avoid triggering undefined behaviour.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
[jstultz: include trivial milisecond->microsecond correction noticed
by Andy]
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Showing 2 changed files with 17 additions and 0 deletions Side-by-side Diff

include/linux/time.h
... ... @@ -99,6 +99,19 @@
99 99 return true;
100 100 }
101 101  
  102 +static inline bool timeval_valid(const struct timeval *tv)
  103 +{
  104 + /* Dates before 1970 are bogus */
  105 + if (tv->tv_sec < 0)
  106 + return false;
  107 +
  108 + /* Can't have more microseconds then a second */
  109 + if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC)
  110 + return false;
  111 +
  112 + return true;
  113 +}
  114 +
102 115 extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
103 116  
104 117 #define CURRENT_TIME (current_kernel_time())
... ... @@ -196,6 +196,10 @@
196 196 if (tv) {
197 197 if (copy_from_user(&user_tv, tv, sizeof(*tv)))
198 198 return -EFAULT;
  199 +
  200 + if (!timeval_valid(&user_tv))
  201 + return -EINVAL;
  202 +
199 203 new_ts.tv_sec = user_tv.tv_sec;
200 204 new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC;
201 205 }