Received: by 2002:a25:ad19:0:0:0:0:0 with SMTP id y25csp7154232ybi; Mon, 8 Jul 2019 15:44:47 -0700 (PDT) X-Google-Smtp-Source: APXvYqyJi5KAVvB97pFOZVkwD5f4kwCt1tgqKDkZfZ85AWopyKKOsr1eYMsTOL6S5RkJ83MZ1yEX X-Received: by 2002:a17:90a:ac0e:: with SMTP id o14mr29036044pjq.142.1562625887442; Mon, 08 Jul 2019 15:44:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1562625887; cv=none; d=google.com; s=arc-20160816; b=hYeV/ie9Ozt7GN7eulfKKd25IrGSgbllGhwN2oj2R2WfnXoeR38SHLIiEQruW9Wjgv J5gkgG09YcHgFJXaLoipCvmx6bWIDqFnfE8yidaIlMyYWTGp6PvJY/af7dPl3+wjjvnj 2eUnEUDD68Rt4KX0s+2A/jAb2TbVIXZRqXr2T06S4NgIE519uGAjt3FmRyh4g4Sbbapl quWOtMJ7aUUATfZ6v8CesMrG39gqEB3OYu9afpZIKSzsIX4ZaekYXK35UEkSAoFpNZdT /dDlJbbuhhLdrs9mEhWjGAnWLANGpLHdsOq2uDW1umWATlYwr1Rid0rnF56knOCm37ed suuw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:dkim-signature; bh=va2IqGms4zwARolaxGifymkA8dWqhnjJfJEjqFTqRUA=; b=X6BQHDQCky0cKJyScUbGAKJCVLTLfXiRFsZ30Cg8wfXLvMT5PzlBMP1ojzCBlPYr97 DAQJjGIN7Dsb1B4SgXKCPYdg/sfPsQYqmtQ51X4yVGQZS2NDmWh4Tu9YmHKKZ0+uIrZd y87RJusb5eIvj9ot4NkqhDUryisBq5LTOa0438lGxOKQRC+6dzWtFJJkN1jR0BF4Zy8V R6iNwT/TFeLLSuZbRhgat8wNJppWq3x0c/ISAKtGpvM0D/mYGtTwbGvx9n0IqIAzIieT e1/twRZkfUXYlqlyNY1cjhh6Gw+Yyfd/kpNL9JAqpwFCuAur59jEQ5Xlz2wIF8h7+Rza zphg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=B62llil3; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a23si17978955pls.189.2019.07.08.15.44.32; Mon, 08 Jul 2019 15:44:47 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=B62llil3; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2391554AbfGHRJN (ORCPT + 99 others); Mon, 8 Jul 2019 13:09:13 -0400 Received: from mail-vk1-f202.google.com ([209.85.221.202]:45334 "EHLO mail-vk1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390994AbfGHRJL (ORCPT ); Mon, 8 Jul 2019 13:09:11 -0400 Received: by mail-vk1-f202.google.com with SMTP id x83so6792708vkx.12 for ; Mon, 08 Jul 2019 10:09:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=va2IqGms4zwARolaxGifymkA8dWqhnjJfJEjqFTqRUA=; b=B62llil3Fe4KzeXZEaBbD+00lGLnt61xZThwbT0g6IZl70whfkLgUD6l34hNGVCkHT 1XnLhu2ClICsG1ZP+VNktTAQx/P6j3YB6/j+5u70823Y2qvPdZJDEIRXRbOenMh1hpPP GSHE0OkiCT199jGkL1qB9jQVmf/D5xM3xl23+MYa2Z+ObxwJgvIxgeg+Qxu7/SXwDL7B FsNT+911aCa7KFAtwfmkM17dtznwJG3ibBxxM/tlmnyjdcoOIdyybcxyKNrZMUYmA9UV 9YH2/5ecSLu43JAiNIRdh+iXemCTUQqtbW+fFY4QzbvLVelQ8VLKJWV1P7oHoBSpKz/0 /BhQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=va2IqGms4zwARolaxGifymkA8dWqhnjJfJEjqFTqRUA=; b=BEoguiMxTg7cZ8N4vlBb1/woS1G7E5jTQ7VZhKFeieALVPIkOaXylVFGXEoM9ce+/o KGiiR/G9QyLThPrFtkxuKnhInjT1cWHq17umNl5wdm9q1dGQ12LiMRKVweX5sUjFcKmN tl35tgv2YdRQPmKHF35LDK9JJxIalJ4MBXqhuYpg4Q79rcCgleHkLFi3e6oBAkIitLNX 1BQVF50iezgkss57VxwZb13AvzMMOZCaWWtZdnM2LVR1k0PgX466b0kPZKTO+v5HRig5 6SMzpGxf+FZ4kIgma7bWPs8dJxG9vAGVfLz31+vzBiIhcy/zNmzC5lMVIBUpRYOx/TMT nD1g== X-Gm-Message-State: APjAAAUq4f95xffQO8Bc1eS5OojcuJgRPG1W9EIPSSRCoiOzz1nw6Y2F 8r5dHJ5XwOIo6GUKnKiYYPhcTZBRTw== X-Received: by 2002:ab0:66d2:: with SMTP id d18mr10407237uaq.101.1562605750505; Mon, 08 Jul 2019 10:09:10 -0700 (PDT) Date: Mon, 8 Jul 2019 19:07:07 +0200 In-Reply-To: <20190708170706.174189-1-elver@google.com> Message-Id: <20190708170706.174189-6-elver@google.com> Mime-Version: 1.0 References: <20190708170706.174189-1-elver@google.com> X-Mailer: git-send-email 2.22.0.410.gd8fdbe21b5-goog Subject: [PATCH v5 5/5] mm/kasan: Add object validation in ksize() From: Marco Elver To: elver@google.com Cc: linux-kernel@vger.kernel.org, Kees Cook , Andrey Ryabinin , Dmitry Vyukov , Alexander Potapenko , Andrey Konovalov , Christoph Lameter , Pekka Enberg , David Rientjes , Joonsoo Kim , Andrew Morton , Mark Rutland , kasan-dev@googlegroups.com, linux-mm@kvack.org Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org ksize() has been unconditionally unpoisoning the whole shadow memory region associated with an allocation. This can lead to various undetected bugs, for example, double-kzfree(). Specifically, kzfree() uses ksize() to determine the actual allocation size, and subsequently zeroes the memory. Since ksize() used to just unpoison the whole shadow memory region, no invalid free was detected. This patch addresses this as follows: 1. Add a check in ksize(), and only then unpoison the memory region. 2. Preserve kasan_unpoison_slab() semantics by explicitly unpoisoning the shadow memory region using the size obtained from __ksize(). Tested: 1. With SLAB allocator: a) normal boot without warnings; b) verified the added double-kzfree() is detected. 2. With SLUB allocator: a) normal boot without warnings; b) verified the added double-kzfree() is detected. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=199359 Signed-off-by: Marco Elver Acked-by: Kees Cook Cc: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Andrey Konovalov Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Cc: Andrew Morton Cc: Mark Rutland Cc: Kees Cook Cc: kasan-dev@googlegroups.com Cc: linux-kernel@vger.kernel.org Cc: linux-mm@kvack.org --- v4: * Prefer WARN_ON_ONCE() instead of BUG_ON(). --- include/linux/kasan.h | 7 +++++-- mm/slab_common.c | 22 +++++++++++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index b40ea104dd36..cc8a03cc9674 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -76,8 +76,11 @@ void kasan_free_shadow(const struct vm_struct *vm); int kasan_add_zero_shadow(void *start, unsigned long size); void kasan_remove_zero_shadow(void *start, unsigned long size); -size_t ksize(const void *); -static inline void kasan_unpoison_slab(const void *ptr) { ksize(ptr); } +size_t __ksize(const void *); +static inline void kasan_unpoison_slab(const void *ptr) +{ + kasan_unpoison_shadow(ptr, __ksize(ptr)); +} size_t kasan_metadata_size(struct kmem_cache *cache); bool kasan_save_enable_multi_shot(void); diff --git a/mm/slab_common.c b/mm/slab_common.c index b7c6a40e436a..a09bb10aa026 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -1613,7 +1613,27 @@ EXPORT_SYMBOL(kzfree); */ size_t ksize(const void *objp) { - size_t size = __ksize(objp); + size_t size; + + if (WARN_ON_ONCE(!objp)) + return 0; + /* + * We need to check that the pointed to object is valid, and only then + * unpoison the shadow memory below. We use __kasan_check_read(), to + * generate a more useful report at the time ksize() is called (rather + * than later where behaviour is undefined due to potential + * use-after-free or double-free). + * + * If the pointed to memory is invalid we return 0, to avoid users of + * ksize() writing to and potentially corrupting the memory region. + * + * We want to perform the check before __ksize(), to avoid potentially + * crashing in __ksize() due to accessing invalid metadata. + */ + if (unlikely(objp == ZERO_SIZE_PTR) || !__kasan_check_read(objp, 1)) + return 0; + + size = __ksize(objp); /* * We assume that ksize callers could use whole allocated area, * so we need to unpoison this area. -- 2.22.0.410.gd8fdbe21b5-goog