]> Pileus Git - ~andy/linux/blobdiff - kernel/time/timekeeping.c
time: Avoid potential shift overflow with large shift values
[~andy/linux] / kernel / time / timekeeping.c
index 898bef066a448e8474f68965284ac1f1536a52c1..a5a9389c4c3090221d1b31bb89512cba5b36af0c 100644 (file)
@@ -115,6 +115,7 @@ static void tk_xtime_add(struct timekeeper *tk, const struct timespec *ts)
 {
        tk->xtime_sec += ts->tv_sec;
        tk->xtime_nsec += (u64)ts->tv_nsec << tk->shift;
+       tk_normalize_xtime(tk);
 }
 
 static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm)
@@ -276,7 +277,7 @@ static void timekeeping_forward_now(struct timekeeper *tk)
        tk->xtime_nsec += cycle_delta * tk->mult;
 
        /* If arch requires, add in gettimeoffset() */
-       tk->xtime_nsec += arch_gettimeoffset() << tk->shift;
+       tk->xtime_nsec += (u64)arch_gettimeoffset() << tk->shift;
 
        tk_normalize_xtime(tk);
 
@@ -1183,9 +1184,9 @@ static void update_wall_time(void)
        * the vsyscall implementations are converted to use xtime_nsec
        * (shifted nanoseconds), this can be killed.
        */
-       remainder = tk->xtime_nsec & ((1 << tk->shift) - 1);
+       remainder = tk->xtime_nsec & ((1ULL << tk->shift) - 1);
        tk->xtime_nsec -= remainder;
-       tk->xtime_nsec += 1 << tk->shift;
+       tk->xtime_nsec += 1ULL << tk->shift;
        tk->ntp_error += remainder << tk->ntp_error_shift;
 
        /*