From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752097AbdFLNCf (ORCPT ); Mon, 12 Jun 2017 09:02:35 -0400 Received: from mx1.redhat.com ([209.132.183.28]:46050 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751974AbdFLNCe (ORCPT ); Mon, 12 Jun 2017 09:02:34 -0400 DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 93263C04B929 Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=prarit@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 93263C04B929 From: Prarit Bhargava To: linux-kernel@vger.kernel.org Cc: Prarit Bhargava , John Stultz , Thomas Gleixner , Stephen Boyd Subject: [PATCH] time/alarmtimer: Add bounds checking for the timer interval and expiration Date: Mon, 12 Jun 2017 09:02:30 -0400 Message-Id: <1497272550-3337-1-git-send-email-prarit@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Mon, 12 Jun 2017 13:02:33 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 Cc: John Stultz Cc: Thomas Gleixner Cc: Stephen Boyd --- 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