lkml.org 
[lkml]   [2016]   [Sep]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 105/192] [PATCH 109/135] time: Verify time values in adjtimex ADJ_SETOFFSET to avoid overflow
    Date
    4.4-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    [ Upstream commit 37cf4dc3370fbca0344e23bb96446eb2c3548ba7 ]

    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>
    Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    include/linux/time.h | 26 ++++++++++++++++++++++++++
    kernel/time/ntp.c | 10 ++++++++--
    kernel/time/timekeeping.c | 2 +-
    3 files changed, 35 insertions(+), 3 deletions(-)

    --- a/include/linux/time.h
    +++ b/include/linux/time.h
    @@ -125,6 +125,32 @@ static inline bool timeval_valid(const s

    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 })

    --- a/kernel/time/ntp.c
    +++ b/kernel/time/ntp.c
    @@ -674,8 +674,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
    --- a/kernel/time/timekeeping.c
    +++ b/kernel/time/timekeeping.c
    @@ -958,7 +958,7 @@ int timekeeping_inject_offset(struct tim
    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);

    \
     
     \ /
      Last update: 2016-09-17 09:59    [W:4.059 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site