Commit 5a7780e725d1bb4c3094fcc12f1c5c5faea1e988
1 parent
e760e716d4
Exists in
master
and in
20 other branches
hrtimer: check relative timeouts for overflow
Various user space callers ask for relative timeouts. While we fixed that overflow issue in hrtimer_start(), the sites which convert relative user space values to absolute timeouts themself were uncovered. Instead of putting overflow checks into each place add a function which does the sanity checking and convert all affected callers to use it. Thanks to Frans Pop, who reported the problem and tested the fixes. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Ingo Molnar <mingo@elte.hu> Tested-by: Frans Pop <elendil@planet.nl>
Showing 5 changed files with 29 additions and 22 deletions Side-by-side Diff
include/linux/ktime.h
... | ... | @@ -310,6 +310,8 @@ |
310 | 310 | return ktime_sub_ns(kt, usec * 1000); |
311 | 311 | } |
312 | 312 | |
313 | +extern ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs); | |
314 | + | |
313 | 315 | /* |
314 | 316 | * The resolution of the clocks. The resolution value is returned in |
315 | 317 | * the clock_getres() system call to give application programmers an |
kernel/futex.c
kernel/futex_compat.c
kernel/hrtimer.c
... | ... | @@ -326,6 +326,23 @@ |
326 | 326 | #endif /* BITS_PER_LONG >= 64 */ |
327 | 327 | |
328 | 328 | /* |
329 | + * Add two ktime values and do a safety check for overflow: | |
330 | + */ | |
331 | +ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs) | |
332 | +{ | |
333 | + ktime_t res = ktime_add(lhs, rhs); | |
334 | + | |
335 | + /* | |
336 | + * We use KTIME_SEC_MAX here, the maximum timeout which we can | |
337 | + * return to user space in a timespec: | |
338 | + */ | |
339 | + if (res.tv64 < 0 || res.tv64 < lhs.tv64 || res.tv64 < rhs.tv64) | |
340 | + res = ktime_set(KTIME_SEC_MAX, 0); | |
341 | + | |
342 | + return res; | |
343 | +} | |
344 | + | |
345 | +/* | |
329 | 346 | * Check, whether the timer is on the callback pending list |
330 | 347 | */ |
331 | 348 | static inline int hrtimer_cb_pending(const struct hrtimer *timer) |
... | ... | @@ -682,13 +699,7 @@ |
682 | 699 | */ |
683 | 700 | orun++; |
684 | 701 | } |
685 | - timer->expires = ktime_add(timer->expires, interval); | |
686 | - /* | |
687 | - * Make sure, that the result did not wrap with a very large | |
688 | - * interval. | |
689 | - */ | |
690 | - if (timer->expires.tv64 < 0) | |
691 | - timer->expires = ktime_set(KTIME_SEC_MAX, 0); | |
702 | + timer->expires = ktime_add_safe(timer->expires, interval); | |
692 | 703 | |
693 | 704 | return orun; |
694 | 705 | } |
... | ... | @@ -839,7 +850,7 @@ |
839 | 850 | new_base = switch_hrtimer_base(timer, base); |
840 | 851 | |
841 | 852 | if (mode == HRTIMER_MODE_REL) { |
842 | - tim = ktime_add(tim, new_base->get_time()); | |
853 | + tim = ktime_add_safe(tim, new_base->get_time()); | |
843 | 854 | /* |
844 | 855 | * CONFIG_TIME_LOW_RES is a temporary way for architectures |
845 | 856 | * to signal that they simply return xtime in |
846 | 857 | |
... | ... | @@ -848,16 +859,8 @@ |
848 | 859 | * timeouts. This will go away with the GTOD framework. |
849 | 860 | */ |
850 | 861 | #ifdef CONFIG_TIME_LOW_RES |
851 | - tim = ktime_add(tim, base->resolution); | |
862 | + tim = ktime_add_safe(tim, base->resolution); | |
852 | 863 | #endif |
853 | - /* | |
854 | - * Careful here: User space might have asked for a | |
855 | - * very long sleep, so the add above might result in a | |
856 | - * negative number, which enqueues the timer in front | |
857 | - * of the queue. | |
858 | - */ | |
859 | - if (tim.tv64 < 0) | |
860 | - tim.tv64 = KTIME_MAX; | |
861 | 864 | } |
862 | 865 | timer->expires = tim; |
863 | 866 |
kernel/posix-timers.c
... | ... | @@ -767,9 +767,11 @@ |
767 | 767 | /* SIGEV_NONE timers are not queued ! See common_timer_get */ |
768 | 768 | if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) { |
769 | 769 | /* Setup correct expiry time for relative timers */ |
770 | - if (mode == HRTIMER_MODE_REL) | |
771 | - timer->expires = ktime_add(timer->expires, | |
772 | - timer->base->get_time()); | |
770 | + if (mode == HRTIMER_MODE_REL) { | |
771 | + timer->expires = | |
772 | + ktime_add_safe(timer->expires, | |
773 | + timer->base->get_time()); | |
774 | + } | |
773 | 775 | return 0; |
774 | 776 | } |
775 | 777 |