From patchwork Wed Aug 17 19:18:50 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Stultz X-Patchwork-Id: 9286365 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 8824C60459 for ; Wed, 17 Aug 2016 19:19:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 76469295DE for ; Wed, 17 Aug 2016 19:19:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6AC38296DB; Wed, 17 Aug 2016 19:19:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C63D7295DE for ; Wed, 17 Aug 2016 19:19:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753564AbcHQTTF (ORCPT ); Wed, 17 Aug 2016 15:19:05 -0400 Received: from mail-pf0-f179.google.com ([209.85.192.179]:36284 "EHLO mail-pf0-f179.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753556AbcHQTTD (ORCPT ); Wed, 17 Aug 2016 15:19:03 -0400 Received: by mail-pf0-f179.google.com with SMTP id h186so39993549pfg.3 for ; Wed, 17 Aug 2016 12:18:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=BRaLnal3XXKytWpTc5KziIfXq4y3HRUFOkU5WmllOG0=; b=IhpvkqY3n8bNGU+75kNYvZtPA7rmJsHTYtbDZ0cdB1cb97Tne2X8X47+p6VgQLWR8X vRYmV/HQYxk1ackocX4BP7Xn9GyPJNEmjGfOBSyWwND46RnfrjkbZuTc3jUPumRAyMxM DJNl+Aywo6DCqKb+vjC37Ek5jIAiu0aV/CYD4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=BRaLnal3XXKytWpTc5KziIfXq4y3HRUFOkU5WmllOG0=; b=SQtrjiC4a0ktS4G0LRHK4aIodsMA203yf7Mcdb0XlSoSqSrcJtnS8Im7ekxfLm+pPl mXKt/o074HxajbeRVrQbu/r295LhmK3AcTHkZqz9/1XnSYTKEITCDTHHH8dHymRdd5U8 jMlHytn+HzXriSfoNS+e6MtCO2B4YLwHeMs42uquiD38bvbzc2NFt3L9LQExYoBAJvWW f5quFaaIzDTUlZ/zB14EuhaftwgpyxqBLaJ7hR62i0IygMVPuzS02XJI+cylMvsh3Y3t +eJRY8J8ipOivUyDwG0ArA4CFS0FSzJTopAPZr3jjP8vKIOmZhtxVDmqQZwkmSXz/6GQ z4qw== X-Gm-Message-State: AEkoouteEdOFODR10PpWSS/uUOgKw+CMPlOo/TL+UJQoaMecfeGcrsKh2O2k7H5GSreaiBCa X-Received: by 10.98.70.8 with SMTP id t8mr8837363pfa.36.1471461538139; Wed, 17 Aug 2016 12:18:58 -0700 (PDT) Received: from localhost.localdomain (c-73-67-244-238.hsd1.or.comcast.net. [73.67.244.238]) by smtp.gmail.com with ESMTPSA id g5sm49072337pfg.0.2016.08.17.12.18.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 17 Aug 2016 12:18:57 -0700 (PDT) From: John Stultz To: Chen Yu Cc: John Stultz , Thomas Gleixner , "Rafael J. Wysocki" , Janek Kozicki , Xunlei Pang , Zhang Rui , linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org Subject: [PATCH] timekeeping: Cap array access in timekeeping_debug to protect against invalid sleep times Date: Wed, 17 Aug 2016 12:18:50 -0700 Message-Id: <1471461530-19575-1-git-send-email-john.stultz@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1469892465-15853-1-git-send-email-yu.c.chen@intel.com> References: <1469892465-15853-1-git-send-email-yu.c.chen@intel.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP It was reported that hibernation could fail on the 2nd attempt, where the system hangs at hibernate() -> syscore_resume() -> i8237A_resume() -> claim_dma_lock(), because the lock has already been taken. However there is actually no other process would like to grab this lock on that problematic platform. Further investigation showed that the problem is triggered by setting /sys/power/pm_trace to 1 before the 1st hibernation. Since once pm_trace is enabled, the rtc becomes unmeaningful after suspend, and meanwhile some BIOSes would like to adjust the 'invalid' tsc(e.g, smaller than 1970) to the release date of that motherboard during POST stage, thus after resumed, it may seem that the system had a significant long sleep time might due to meaningless tsc or RTC delta. Then in timekeeping_resume -> tk_debug_account_sleep_time, if the bit31 of the sleep time happened to be set to 1, the fls returns 32 and then we add 1 to sleep_time_bin[32], which caused a memory overwritten. As depicted by System.map: ffffffff81c9d080 b sleep_time_bin ffffffff81c9d100 B dma_spin_lock the dma_spin_lock.val is set to 1, which caused this problem. This patch adds a sanity check in tk_debug_account_sleep_time() to ensure we don't index past the sleep_time_bin array. Cc: Thomas Gleixner Cc: Rafael J. Wysocki Cc: Janek Kozicki Cc: Chen Yu Cc: Xunlei Pang Cc: Zhang Rui Cc: linux-kernel@vger.kernel.org Cc: linux-pm@vger.kernel.org Reported-by: Janek Kozicki Reported-by: Chen Yu [jstultz: Problem diagnosed and original patch by Chen Yu, I've solved the issue slightly differently, but borrowed his excelent explanation of of the issue here.] Signed-off-by: John Stultz --- kernel/time/timekeeping_debug.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/time/timekeeping_debug.c b/kernel/time/timekeeping_debug.c index f6bd652..107310a6 100644 --- a/kernel/time/timekeeping_debug.c +++ b/kernel/time/timekeeping_debug.c @@ -23,7 +23,9 @@ #include "timekeeping_internal.h" -static unsigned int sleep_time_bin[32] = {0}; +#define NUM_BINS 32 + +static unsigned int sleep_time_bin[NUM_BINS] = {0}; static int tk_debug_show_sleep_time(struct seq_file *s, void *data) { @@ -69,6 +71,9 @@ late_initcall(tk_debug_sleep_time_init); void tk_debug_account_sleep_time(struct timespec64 *t) { - sleep_time_bin[fls(t->tv_sec)]++; + /* Cap bin index so we don't overflow the array */ + int bin = min(fls(t->tv_sec), NUM_BINS-1); + + sleep_time_bin[bin]++; }