Messages in this thread Patch in this message | | | From | Prarit Bhargava <> | Subject | [PATCH] time/alarmtimer: Add bounds checking for the timer interval and expiration | Date | Mon, 12 Jun 2017 09:02:30 -0400 |
| |
Running the syzkaller timer_hang_poc.c (https://groups.google.com/forum/#!topic/syzkaller/355tWdc8oHY) causes a kernel hang by passing in a time that results in the timer being started with an expiration that exceeds KTIME_MAX.
Check for overflow values of expiration (exp) and interval.
Also cleanup the code. Set and check the values, and then modify the timer.
Signed-off-by: Prarit Bhargava <prarit@redhat.com> Cc: John Stultz <john.stultz@linaro.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Stephen Boyd <sboyd@codeaurora.org> --- kernel/time/alarmtimer.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 5cb5b0008d97..19400dee83c9 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -643,7 +643,7 @@ static int alarm_timer_set(struct k_itimer *timr, int flags, struct itimerspec64 *new_setting, struct itimerspec64 *old_setting) { - ktime_t exp; + ktime_t exp, interval; if (!rtcdev) return -ENOTSUPP; @@ -654,12 +654,6 @@ static int alarm_timer_set(struct k_itimer *timr, int flags, if (old_setting) alarm_timer_get(timr, old_setting); - /* If the timer was already set, cancel it */ - if (alarm_try_to_cancel(&timr->it.alarm.alarmtimer) < 0) - return TIMER_RETRY; - - /* start the timer */ - timr->it.alarm.interval = timespec64_to_ktime(new_setting->it_interval); exp = timespec64_to_ktime(new_setting->it_value); /* Convert (if necessary) to absolute time */ if (flags != TIMER_ABSTIME) { @@ -668,7 +662,19 @@ static int alarm_timer_set(struct k_itimer *timr, int flags, now = alarm_bases[timr->it.alarm.alarmtimer.type].gettime(); exp = ktime_add(now, exp); } + if (exp < 0) + exp = KTIME_MAX; + interval = timespec64_to_ktime(new_setting->it_interval); + if (interval < 0) + interval = KTIME_MAX; + + /* If the timer was already set, cancel it */ + if (alarm_try_to_cancel(&timr->it.alarm.alarmtimer) < 0) + return TIMER_RETRY; + + /* start the timer */ + timr->it.alarm.interval = interval; alarm_start(&timr->it.alarm.alarmtimer, exp); return 0; } -- 1.7.9.3
| |