From patchwork Tue Nov 27 05:23:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Khalid Elmously X-Patchwork-Id: 1003611 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 433sf43MgMz9s6w; Tue, 27 Nov 2018 16:24:12 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1gRVqu-0007dj-AW; Tue, 27 Nov 2018 05:24:04 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1gRVqs-0007dM-UP for kernel-team@lists.ubuntu.com; Tue, 27 Nov 2018 05:24:02 +0000 Received: from mail-qk1-f198.google.com ([209.85.222.198]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1gRVqs-00078y-Kt for kernel-team@lists.ubuntu.com; Tue, 27 Nov 2018 05:24:02 +0000 Received: by mail-qk1-f198.google.com with SMTP id 67so21376647qkj.18 for ; Mon, 26 Nov 2018 21:24:02 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=CuOpqjSnKD+3Dj/U7OrZyaxsOUZS0o9WhD3FzlB/IdI=; b=dmsOHvLi0qiB40OzcICd0n2jiwfFSYlfYWgi3I9ihs2saP390xTEjcCvM6V3eAW3XL xAE9JCcyL6uxtXKdhw99IWCfWAEOqvQSkgOw9fg+SezoNXokXBJtPUFf0FhCJzbSYBKe jr14oS1FhL0db1WXphUoQdwtR2PW7L7t4MPm947G4WsKFb5ifYG24mfglgfU2+H9fCOo AZd6oS0C9nvCbVUtV+TMxKGsnim5INYxN4nGG9axr9Qta2Wnl6X5hsU341xSEy/H42hX 4VXztU9uVUxwWAcZwRzOpY5Qq1f7XmE9kLbZDdknAywa/ofSClvee5FOcjID+2TgrIRM H6SA== X-Gm-Message-State: AGRZ1gIS+UAiNCNrJBl0FsZvyFGwT+Bzk39XGvjr/VGHul4TNaGSDldU PBxY4kTgfsZ0tB3dhtmbGuQvag8A1kX9smUr9924KWODmVgKTZHfSb+1Fk7/ZB1KNILYNeRap78 W32pIM41VUFALe1fHC0mfoGP4DtbTnxk2ucjf8UV8JA== X-Received: by 2002:aed:20ca:: with SMTP id 68mr29393528qtb.296.1543296241521; Mon, 26 Nov 2018 21:24:01 -0800 (PST) X-Google-Smtp-Source: AJdET5f1CwpoxQHV6NYpCKvE3OU4Qo0njf95onPsTSV2s/EeyUKEPMe9ZonD2f3XiIGItsLel5hnFA== X-Received: by 2002:aed:20ca:: with SMTP id 68mr29393517qtb.296.1543296241254; Mon, 26 Nov 2018 21:24:01 -0800 (PST) Received: from kbuntu.fuzzbuzz.org (198-16-164-194.on.cable.ebox.net. [198.16.164.194]) by smtp.gmail.com with ESMTPSA id e5sm1141188qtr.52.2018.11.26.21.24.00 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 26 Nov 2018 21:24:00 -0800 (PST) From: Khalid Elmously To: kernel-team@lists.ubuntu.com Subject: [SRU][Bionic][PATCH 1/1] posix-timers: Sanitize overrun handling Date: Tue, 27 Nov 2018 00:23:16 -0500 Message-Id: <20181127052318.364-2-khalid.elmously@canonical.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181127052318.364-1-khalid.elmously@canonical.com> References: <20181127052318.364-1-khalid.elmously@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Thomas Gleixner CVE-2018-12896 The posix timer overrun handling is broken because the forwarding functions can return a huge number of overruns which does not fit in an int. As a consequence timer_getoverrun(2) and siginfo::si_overrun can turn into random number generators. The k_clock::timer_forward() callbacks return a 64 bit value now. Make k_itimer::ti_overrun[_last] 64bit as well, so the kernel internal accounting is correct. 3Remove the temporary (int) casts. Add a helper function which clamps the overrun value returned to user space via timer_getoverrun(2) or siginfo::si_overrun limited to a positive value between 0 and INT_MAX. INT_MAX is an indicator for user space that the overrun value has been clamped. Reported-by: Team OWL337 Signed-off-by: Thomas Gleixner Acked-by: John Stultz Cc: Peter Zijlstra Cc: Michael Kerrisk Link: https://lkml.kernel.org/r/20180626132705.018623573@linutronix.de (cherry picked from commit 78c9c4dfbf8c04883941445a195276bb4bb92c76) Signed-off-by: Khalid Elmously Acked-by: Tyler Hicks Acked-by: Kleber Sacilotto de Souza --- include/linux/posix-timers.h | 4 ++-- kernel/time/posix-cpu-timers.c | 2 +- kernel/time/posix-timers.c | 29 +++++++++++++++++++---------- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 672c4f32311e..437a539898ae 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -82,8 +82,8 @@ struct k_itimer { clockid_t it_clock; timer_t it_id; int it_active; - int it_overrun; - int it_overrun_last; + s64 it_overrun; + s64 it_overrun_last; int it_requeue_pending; int it_sigev_notify; ktime_t it_interval; diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index 1f27887aa194..0f5f019c6645 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -84,7 +84,7 @@ static void bump_cpu_timer(struct k_itimer *timer, u64 now) continue; timer->it.cpu.expires += incr; - timer->it_overrun += 1 << i; + timer->it_overrun += 1LL << i; delta -= incr; } } diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 708992708332..3192a986a483 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -283,6 +283,17 @@ static __init int init_posix_timers(void) } __initcall(init_posix_timers); +/* + * The siginfo si_overrun field and the return value of timer_getoverrun(2) + * are of type int. Clamp the overrun value to INT_MAX + */ +static inline int timer_overrun_to_int(struct k_itimer *timr, int baseval) +{ + s64 sum = timr->it_overrun_last + (s64)baseval; + + return sum > (s64)INT_MAX ? INT_MAX : (int)sum; +} + static void common_hrtimer_rearm(struct k_itimer *timr) { struct hrtimer *timer = &timr->it.real.timer; @@ -290,9 +301,8 @@ static void common_hrtimer_rearm(struct k_itimer *timr) if (!timr->it_interval) return; - timr->it_overrun += (unsigned int) hrtimer_forward(timer, - timer->base->get_time(), - timr->it_interval); + timr->it_overrun += hrtimer_forward(timer, timer->base->get_time(), + timr->it_interval); hrtimer_restart(timer); } @@ -321,10 +331,10 @@ void posixtimer_rearm(struct siginfo *info) timr->it_active = 1; timr->it_overrun_last = timr->it_overrun; - timr->it_overrun = -1; + timr->it_overrun = -1LL; ++timr->it_requeue_pending; - info->si_overrun += timr->it_overrun_last; + info->si_overrun = timer_overrun_to_int(timr, info->si_overrun); } unlock_timer(timr, flags); @@ -418,9 +428,8 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer) now = ktime_add(now, kj); } #endif - timr->it_overrun += (unsigned int) - hrtimer_forward(timer, now, - timr->it_interval); + timr->it_overrun += hrtimer_forward(timer, now, + timr->it_interval); ret = HRTIMER_RESTART; ++timr->it_requeue_pending; timr->it_active = 1; @@ -524,7 +533,7 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event, new_timer->it_id = (timer_t) new_timer_id; new_timer->it_clock = which_clock; new_timer->kclock = kc; - new_timer->it_overrun = -1; + new_timer->it_overrun = -1LL; if (event) { rcu_read_lock(); @@ -789,7 +798,7 @@ SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) if (!timr) return -EINVAL; - overrun = timr->it_overrun_last; + overrun = timer_overrun_to_int(timr, 0); unlock_timer(timr, flags); return overrun;