From patchwork Wed Aug 17 21:42:08 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kees Cook X-Patchwork-Id: 9286619 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 EDC3760839 for ; Wed, 17 Aug 2016 21:42:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DF9042950D for ; Wed, 17 Aug 2016 21:42:43 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D3AE629512; Wed, 17 Aug 2016 21:42:43 +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 6D51B2950D for ; Wed, 17 Aug 2016 21:42:41 +0000 (UTC) Received: (qmail 22165 invoked by uid 550); 17 Aug 2016 21:42:35 -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: Reply-To: kernel-hardening@lists.openwall.com Delivered-To: mailing list kernel-hardening@lists.openwall.com Received: (qmail 22144 invoked from network); 17 Aug 2016 21:42:34 -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=LagCJUZnn6oUbw0dAYbdkY/9DQynqHuEyR/5JvMCuVQ=; b=WaSJGwyfOcLN9BiWC3gkW22s9Irnf/Ln31cwM3UfZc17onec9mErO+l2gGTLyMRQ3a SesysRO5tcUh37QJANSar1OkC5dhzZkQnR/Jz5oCRb4OqaWg3r0JWtF7yQ2+gPBQGUY2 +xp4HYJ3oHMJmUTh2ONi4jZUc4OfohMmw8XyM= 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=LagCJUZnn6oUbw0dAYbdkY/9DQynqHuEyR/5JvMCuVQ=; b=dpaxrXGy16nl0rM6LB4p2Djz3v/4HGtGnF/RhrrJ8A4CB1kBx7R9AEv268+yINPx6f +kd1KTnoDqtLWUOkytm5wy4WhekMbNX1IGeJQLr4IZyw3lFPVWDREw4SRrLlyuO5wsO8 g5chSDaivAb9i2h99p6UQ1SgzFtdeTVFdevO3RZojH093gf/QbatPBKKpeoMNILq/i0p pVD6MdEk/Go/u1teJcmhfcCtr0enkDjum9w6yXg6hRUBJWIi+wis9dYGyQNu5Zq+4egP 7xZ9JzatZgCW1n/+/7KmFl09gqLfb0LQeCMSrE9AuS17sCe5jEvTY9HdpPiWAXWrSJOV nEAw== X-Gm-Message-State: AEkoousuC5TJFGVGcpM3m9KKOTVB8xq5ANVFdeny4o2DdC7hDXlu8tvxDCWxoNmT1iXwzWd3 X-Received: by 10.66.100.202 with SMTP id fa10mr78041178pab.106.1471470142056; Wed, 17 Aug 2016 14:42:22 -0700 (PDT) From: Kees Cook To: "Paul E . McKenney" Cc: Kees Cook , Laura Abbott , Steven Rostedt , Daniel Micay , Joe Perches , Stephen Boyd , Syed Rameez Mustafa , Arnd Bergmann , Greg Kroah-Hartman , Josh Triplett , Mathieu Desnoyers , Lai Jiangshan , "Aneesh Kumar K.V" , "Kirill A. Shutemov" , Michael Ellerman , Andrew Morton , Dan Williams , Jan Kara , Thomas Gleixner , Josef Bacik , Ingo Molnar , Tejun Heo , Andrey Ryabinin , Nikolay Aleksandrov , Dmitry Vyukov , linux-kernel@vger.kernel.org, kernel-hardening@lists.openwall.com Date: Wed, 17 Aug 2016 14:42:08 -0700 Message-Id: <1471470132-29499-2-git-send-email-keescook@chromium.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1471470132-29499-1-git-send-email-keescook@chromium.org> References: <1471470132-29499-1-git-send-email-keescook@chromium.org> Subject: [kernel-hardening] [PATCH v3 1/5] list: Split list_add() debug checking into separate function X-Virus-Scanned: ClamAV using ClamSMTP Right now, __list_add() code is repeated either in list.h or in list_debug.c, but only the debug checks are the different part. This extracts the checking into a separate function and consolidates __list_add(). Additionally this __list_add_debug() will stop list manipulations if a corruption is detected, instead of allowing for further corruption that may lead to even worse conditions. This is slight refactoring of the same hardening done in PaX and Grsecurity. Signed-off-by: Kees Cook --- include/linux/list.h | 22 ++++++++++++++++------ lib/list_debug.c | 48 +++++++++++++++++++++++------------------------- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/include/linux/list.h b/include/linux/list.h index 5183138aa932..0ed58591538e 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -28,27 +28,37 @@ static inline void INIT_LIST_HEAD(struct list_head *list) list->prev = list; } +#ifdef CONFIG_DEBUG_LIST +extern bool __list_add_valid(struct list_head *new, + struct list_head *prev, + struct list_head *next); +#else +static inline bool __list_add_valid(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + return true; +} +#endif + /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ -#ifndef CONFIG_DEBUG_LIST static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { + if (!__list_add_valid(new, prev, next)) + return; + next->prev = new; new->next = next; new->prev = prev; WRITE_ONCE(prev->next, new); } -#else -extern void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next); -#endif /** * list_add - add a new entry diff --git a/lib/list_debug.c b/lib/list_debug.c index 3859bf63561c..149dd57b583b 100644 --- a/lib/list_debug.c +++ b/lib/list_debug.c @@ -2,8 +2,7 @@ * Copyright 2006, Red Hat, Inc., Dave Jones * Released under the General Public License (GPL). * - * This file contains the linked list implementations for - * DEBUG_LIST. + * This file contains the linked list validation for DEBUG_LIST. */ #include @@ -13,33 +12,32 @@ #include /* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! + * Check that the data structures for the list manipulations are reasonably + * valid. Failures here indicate memory corruption (and possibly an exploit + * attempt). */ -void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) +bool __list_add_valid(struct list_head *new, struct list_head *prev, + struct list_head *next) { - WARN(next->prev != prev, - "list_add corruption. next->prev should be " - "prev (%p), but was %p. (next=%p).\n", - prev, next->prev, next); - WARN(prev->next != next, - "list_add corruption. prev->next should be " - "next (%p), but was %p. (prev=%p).\n", - next, prev->next, prev); - WARN(new == prev || new == next, - "list_add double add: new=%p, prev=%p, next=%p.\n", - new, prev, next); - next->prev = new; - new->next = next; - new->prev = prev; - WRITE_ONCE(prev->next, new); + if (unlikely(next->prev != prev)) { + WARN(1, "list_add corruption. next->prev should be prev (%p), but was %p. (next=%p).\n", + prev, next->prev, next); + return false; + } + if (unlikely(prev->next != next)) { + WARN(1, "list_add corruption. prev->next should be next (%p), but was %p. (prev=%p).\n", + next, prev->next, prev); + return false; + } + if (unlikely(new == prev || new == next)) { + WARN(1, "list_add double add: new=%p, prev=%p, next=%p.\n", + new, prev, next); + return false; + } + return true; } -EXPORT_SYMBOL(__list_add); +EXPORT_SYMBOL(__list_add_valid); void __list_del_entry(struct list_head *entry) {