From patchwork Fri Feb 3 23:26:51 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 9555307 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 59F93602B7 for ; Fri, 3 Feb 2017 23:27:42 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4625527D29 for ; Fri, 3 Feb 2017 23:27:42 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 397B928425; Fri, 3 Feb 2017 23:27:42 +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=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.wl.linuxfoundation.org (Postfix) with SMTP id 60D4827D29 for ; Fri, 3 Feb 2017 23:27:41 +0000 (UTC) Received: (qmail 5251 invoked by uid 550); 3 Feb 2017 23:27:19 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 5132 invoked from network); 3 Feb 2017 23:27:17 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=HI/qSWEpMyGxoQZ5ys085KIJKO+q7u/Q1a302vYbyvw=; b=h6p2tkRF+8gp9dhrdFIijJQFxhJVJ4Ox6bDN4qo8DF+KwTJdaEG/wvhxPZwZszZwp2 VTT1VMD03/q1UtvAoIkteffCdqlca/xGn/WWvQTaa9KJko3M5cqAkorpMwitASnR7np5 tkOgOMqhDcguHU50e21gG3jQx4A6jQ5Vxgfo8= 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=HI/qSWEpMyGxoQZ5ys085KIJKO+q7u/Q1a302vYbyvw=; b=hU3sIRCGAJjzDh2A1X8XYCk6no+hg5sCejdAFCt+GXi20erLg0M1tyRBERJlfwGWZT O5goMY8/kDcwXlNeeEvDqQ5CF0e7w8h4BXA6rpSIuNKWPkPjc9use8ZntIla4c5OihJd wESJGK0g5zKxBGCnAGSUeUXXn/wLsX449Y66PS7IWOskRzrlipVmFy2NA2dcZxZKD5rq WH7XYDKKTxEXx/NyCb6D73utEIUQh3BmAXMdPcExQdG/hBPLIkOk7xiO4UBsYTXsgD+U sNaMk9NqMFN30WNP80/TMr8ON+V2RIocWXAi5nCJQ4iItafs+rLO3OOxFpmbkPQN/ra6 21/A== X-Gm-Message-State: AIkVDXK/u5UZ/fql95Tbg92dw/fb8qUPIG4n33BRrhhaHw2I1TS2EDXCOkCUW5/P5iZROI1F X-Received: by 10.98.78.66 with SMTP id c63mr21322395pfb.138.1486164425352; Fri, 03 Feb 2017 15:27:05 -0800 (PST) From: Kees Cook To: Peter Zijlstra Cc: Kees Cook , elena.reshetova@intel.com, gregkh@linuxfoundation.org, arnd@arndb.de, tglx@linutronix.de, mingo@kernel.org, h.peter.anvin@intel.com, will.deacon@arm.com, dwindsor@gmail.com, Hans Liljestrand , dhowells@redhat.com, linux-kernel@vger.kernel.org, kernel-hardening@lists.openwall.com Date: Fri, 3 Feb 2017 15:26:51 -0800 Message-Id: <1486164412-7338-4-git-send-email-keescook@chromium.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1486164412-7338-1-git-send-email-keescook@chromium.org> References: <1486164412-7338-1-git-send-email-keescook@chromium.org> Subject: [kernel-hardening] [PATCH 3/4] bug: Switch data corruption check to __must_check X-Virus-Scanned: ClamAV using ClamSMTP The CHECK_DATA_CORRUPTION() macro was designed to have callers do something meaningful/protective on failure. However, using "return false" in the macro too strictly limits the design patterns of callers. Instead, let callers handle the logic test directly, but make sure that the result IS checked by forcing __must_check (which appears to not be able to be used directly on macro expressions). Signed-off-by: Kees Cook --- include/linux/bug.h | 12 +++++++----- lib/list_debug.c | 45 ++++++++++++++++++++++++--------------------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/include/linux/bug.h b/include/linux/bug.h index baff2e8fc8a8..5828489309bb 100644 --- a/include/linux/bug.h +++ b/include/linux/bug.h @@ -124,18 +124,20 @@ static inline enum bug_trap_type report_bug(unsigned long bug_addr, /* * Since detected data corruption should stop operation on the affected - * structures, this returns false if the corruption condition is found. + * structures. Return value must be checked and sanely acted on by caller. */ +static inline __must_check bool check_data_corruption(bool v) { return v; } #define CHECK_DATA_CORRUPTION(condition, fmt, ...) \ - do { \ - if (unlikely(condition)) { \ + check_data_corruption(({ \ + bool corruption = unlikely(condition); \ + if (corruption) { \ if (IS_ENABLED(CONFIG_BUG_ON_DATA_CORRUPTION)) { \ pr_err(fmt, ##__VA_ARGS__); \ BUG(); \ } else \ WARN(1, fmt, ##__VA_ARGS__); \ - return false; \ } \ - } while (0) + corruption; \ + })) #endif /* _LINUX_BUG_H */ diff --git a/lib/list_debug.c b/lib/list_debug.c index 7f7bfa55eb6d..a34db8d27667 100644 --- a/lib/list_debug.c +++ b/lib/list_debug.c @@ -20,15 +20,16 @@ bool __list_add_valid(struct list_head *new, struct list_head *prev, struct list_head *next) { - CHECK_DATA_CORRUPTION(next->prev != prev, - "list_add corruption. next->prev should be prev (%p), but was %p. (next=%p).\n", - prev, next->prev, next); - CHECK_DATA_CORRUPTION(prev->next != next, - "list_add corruption. prev->next should be next (%p), but was %p. (prev=%p).\n", - next, prev->next, prev); - CHECK_DATA_CORRUPTION(new == prev || new == next, - "list_add double add: new=%p, prev=%p, next=%p.\n", - new, prev, next); + if (CHECK_DATA_CORRUPTION(next->prev != prev, + "list_add corruption. next->prev should be prev (%p), but was %p. (next=%p).\n", + prev, next->prev, next) || + CHECK_DATA_CORRUPTION(prev->next != next, + "list_add corruption. prev->next should be next (%p), but was %p. (prev=%p).\n", + next, prev->next, prev) || + CHECK_DATA_CORRUPTION(new == prev || new == next, + "list_add double add: new=%p, prev=%p, next=%p.\n", + new, prev, next)) + return false; return true; } @@ -41,18 +42,20 @@ bool __list_del_entry_valid(struct list_head *entry) prev = entry->prev; next = entry->next; - CHECK_DATA_CORRUPTION(next == LIST_POISON1, - "list_del corruption, %p->next is LIST_POISON1 (%p)\n", - entry, LIST_POISON1); - CHECK_DATA_CORRUPTION(prev == LIST_POISON2, - "list_del corruption, %p->prev is LIST_POISON2 (%p)\n", - entry, LIST_POISON2); - CHECK_DATA_CORRUPTION(prev->next != entry, - "list_del corruption. prev->next should be %p, but was %p\n", - entry, prev->next); - CHECK_DATA_CORRUPTION(next->prev != entry, - "list_del corruption. next->prev should be %p, but was %p\n", - entry, next->prev); + if (CHECK_DATA_CORRUPTION(next == LIST_POISON1, + "list_del corruption, %p->next is LIST_POISON1 (%p)\n", + entry, LIST_POISON1) || + CHECK_DATA_CORRUPTION(prev == LIST_POISON2, + "list_del corruption, %p->prev is LIST_POISON2 (%p)\n", + entry, LIST_POISON2) || + CHECK_DATA_CORRUPTION(prev->next != entry, + "list_del corruption. prev->next should be %p, but was %p\n", + entry, prev->next) || + CHECK_DATA_CORRUPTION(next->prev != entry, + "list_del corruption. next->prev should be %p, but was %p\n", + entry, next->prev)) + return false; + return true; }