lkml.org 
[lkml]   [2021]   [Dec]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 15/23] timekeeping: Really make sure wall_to_monotonic isnt positive
    Date
    From: Yu Liao <liaoyu15@huawei.com>

    commit 4e8c11b6b3f0b6a283e898344f154641eda94266 upstream.

    Even after commit e1d7ba873555 ("time: Always make sure wall_to_monotonic
    isn't positive") it is still possible to make wall_to_monotonic positive
    by running the following code:

    int main(void)
    {
    struct timespec time;

    clock_gettime(CLOCK_MONOTONIC, &time);
    time.tv_nsec = 0;
    clock_settime(CLOCK_REALTIME, &time);
    return 0;
    }

    The reason is that the second parameter of timespec64_compare(), ts_delta,
    may be unnormalized because the delta is calculated with an open coded
    substraction which causes the comparison of tv_sec to yield the wrong
    result:

    wall_to_monotonic = { .tv_sec = -10, .tv_nsec = 900000000 }
    ts_delta = { .tv_sec = -9, .tv_nsec = -900000000 }

    That makes timespec64_compare() claim that wall_to_monotonic < ts_delta,
    but actually the result should be wall_to_monotonic > ts_delta.

    After normalization, the result of timespec64_compare() is correct because
    the tv_sec comparison is not longer misleading:

    wall_to_monotonic = { .tv_sec = -10, .tv_nsec = 900000000 }
    ts_delta = { .tv_sec = -10, .tv_nsec = 100000000 }

    Use timespec64_sub() to ensure that ts_delta is normalized, which fixes the
    issue.

    Fixes: e1d7ba873555 ("time: Always make sure wall_to_monotonic isn't positive")
    Signed-off-by: Yu Liao <liaoyu15@huawei.com>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Cc: stable@vger.kernel.org
    Link: https://lore.kernel.org/r/20211213135727.1656662-1-liaoyu15@huawei.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    kernel/time/timekeeping.c | 3 +--
    1 file changed, 1 insertion(+), 2 deletions(-)

    --- a/kernel/time/timekeeping.c
    +++ b/kernel/time/timekeeping.c
    @@ -966,8 +966,7 @@ int do_settimeofday64(const struct times
    timekeeping_forward_now(tk);

    xt = tk_xtime(tk);
    - ts_delta.tv_sec = ts->tv_sec - xt.tv_sec;
    - ts_delta.tv_nsec = ts->tv_nsec - xt.tv_nsec;
    + ts_delta = timespec64_sub(*ts, xt);

    if (timespec64_compare(&tk->wall_to_monotonic, &ts_delta) > 0) {
    ret = -EINVAL;

    \
     
     \ /
      Last update: 2021-12-20 15:36    [W:4.106 / U:0.040 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site