Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp118355pxb; Fri, 5 Mar 2021 16:24:43 -0800 (PST) X-Google-Smtp-Source: ABdhPJyLUydsmn4VyZ6AZKFd9mkpWmbCSRGqMM4/trf8SRN8TShZGlJ8c1pLFUMlrtLOU/ugf/0s X-Received: by 2002:a50:b5e4:: with SMTP id a91mr11791127ede.173.1614990283663; Fri, 05 Mar 2021 16:24:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1614990283; cv=none; d=google.com; s=arc-20160816; b=CLgygugNThy3NrbfNP2SESlSFiFqvV6rRNZk0QAKD1Ze+NJC/AXBzyVEBYSKKDSj4p 5jLiuOYhEGHoC7+cjhlMN3vhpBMO9tol7VCptV9ce4W1fNaB2dBaKgz598zR5t7LbcLR /DM3mxHAu7YPevCKJM3XM2KzHKmIpwFxXn9HQmMATbGaUY2DYichl1Bm9ZH/PcbT2DMH Oo8wxOkNpVoFzIeK9iFpOLYPQ4ZKti41VJ00BIf3kuXYbQrG/zF4MOIqSPxR4OdHLOkA PgehHP+qO4+iqYvDekqB+/fFUaT6LfvMbHaIpg5xqcnW8v82DYAf7dqCbSKQOvYq5zpM a24A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:references:mime-version :message-id:in-reply-to:date:sender:dkim-signature; bh=UrKz1IN65Ge5y9z4J0tlnwkje+fDVptcypjtSEQF9n0=; b=ccbsNdolGNemn7JTAoVLXgI9JWO4PHxDeawHBgfMUy/ml4S3dWdSybuPmsQQ/kx+Uz TcUEubB73ebWiTDldsMnJ6RHNfroz40+E8nLV2ZJ4g6UUyRihOVoqrYlzF8HZ+sLe75z DPOpqEHEoSZSPyiNMSVm7zq+NI4AXJNdXb0xdPKlkUR9KRSKgtaPpHYmO5sv7QOazLfl UdlQUFB5pYww3lucGqX5F2+WlPy/i+4cKktiq0Fot0xtMeYSKjMMa8jHYKG69UQu7ZIq 5btT+2IkOnbbtSqvUUU4LfuwGOm1dNxLf8S4+4p2g6OttLKdhhkKLxcAW12kJXlWOxwy +k3A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=dojzLQIL; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 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. [23.128.96.18]) by mx.google.com with ESMTP id d5si2306328ejt.487.2021.03.05.16.24.20; Fri, 05 Mar 2021 16:24:43 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=dojzLQIL; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 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 S230034AbhCFAQf (ORCPT + 99 others); Fri, 5 Mar 2021 19:16:35 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47578 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229697AbhCFAQL (ORCPT ); Fri, 5 Mar 2021 19:16:11 -0500 Received: from mail-wr1-x44a.google.com (mail-wr1-x44a.google.com [IPv6:2a00:1450:4864:20::44a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8AA45C06175F for ; Fri, 5 Mar 2021 16:16:11 -0800 (PST) Received: by mail-wr1-x44a.google.com with SMTP id 75so1770310wrl.3 for ; Fri, 05 Mar 2021 16:16:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=UrKz1IN65Ge5y9z4J0tlnwkje+fDVptcypjtSEQF9n0=; b=dojzLQIL1sW7IEUdnLi6xtSbWrkPDPKubWcTLM5dEwi7mJnArnX2D7o2RCe1wjjW0Y 4MLLudxEYhkxBPFalZDREG8+uJ3NOiDQi28pzY6E/JYYbDjRwXjGr6iQLDNwZvV0ft3X e59g2BEGpwT38iDD3ZOSKG9+HvYm0P5Sok7oOxFZbxJbXZKAqaQd3QXZ46HbS1RHWoeH wKFC1iqFA9HUbvXtV6bPigwF/IAfMO1y4GVsBWIsMQ4jvNFbrh5BHKqs0N1j8DLBOADh 6KyRzhdl8N8q1Qi60KvnGRWuSojZGytOvdA1fKuxGmYumdMon1XvDpAYBsU7yl2TEZP2 Z85Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=UrKz1IN65Ge5y9z4J0tlnwkje+fDVptcypjtSEQF9n0=; b=eaunCjttB/5N8Rs4gjDezgQFcDaaDtSxbUII7hFG5e+8osRvlBDSDsuuZrO3l9unfu GjEpHvWXXO32xnjfG3nUeRMjCg6QBXsQEBqDRRWZ8FjnVu/7SkEXIf8IFc3RvovO2piR k1AehxCv+K+JXxG/2TCFOgRno2lhK5oyRZH5VN5NCcpo9wNXGFOjKpIoO7l/1hGlBqse Xn41oDCZhlFfvrV0SN/6IQyKweZisHIjvA83zV/k77D+lP+Q6aKwoN771ahvBpmgFQen vuag264npNp53ek1pOz1MyjSJfzduCNI9l5HIhIqr8wvJquGwFa/uuAoedSKX+4WhOx1 AZ9w== X-Gm-Message-State: AOAM530HqxHmwoEQagzIPFpeXl6RoXWcvO83pHmJwRuxXmU+I4UXYfLk rdo2rAzho6K1Tt+uIozKiZEXq/g+Vf01lq+k Sender: "andreyknvl via sendgmr" X-Received: from andreyknvl3.muc.corp.google.com ([2a00:79e0:15:13:953b:d7cf:2b01:f178]) (user=andreyknvl job=sendgmr) by 2002:adf:f3cc:: with SMTP id g12mr12063558wrp.118.1614989770262; Fri, 05 Mar 2021 16:16:10 -0800 (PST) Date: Sat, 6 Mar 2021 01:15:54 +0100 In-Reply-To: Message-Id: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.30.1.766.gb4fecdf3b7-goog Subject: [PATCH 5/5] kasan, mm: integrate slab init_on_free with HW_TAGS From: Andrey Konovalov To: Alexander Potapenko Cc: Andrew Morton , Catalin Marinas , Will Deacon , Vincenzo Frascino , Dmitry Vyukov , Andrey Ryabinin , Marco Elver , Peter Collingbourne , Evgenii Stepanov , Branislav Rankov , Kevin Brodsky , kasan-dev@googlegroups.com, linux-arm-kernel@lists.infradead.org, linux-mm@kvack.org, linux-kernel@vger.kernel.org, Andrey Konovalov Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This change uses the previously added memory initialization feature of HW_TAGS KASAN routines for slab memory when init_on_free is enabled. With this change, memory initialization memset() is no longer called when both HW_TAGS KASAN and init_on_free are enabled. Instead, memory is initialized in KASAN runtime. For SLUB, the memory initialization memset() is moved into slab_free_hook() that currently directly follows the initialization loop. A new argument is added to slab_free_hook() that indicates whether to initialize the memory or not. To avoid discrepancies with which memory gets initialized that can be caused by future changes, both KASAN hook and initialization memset() are put together and a warning comment is added. Combining setting allocation tags with memory initialization improves HW_TAGS KASAN performance when init_on_free is enabled. Signed-off-by: Andrey Konovalov --- include/linux/kasan.h | 10 ++++++---- mm/kasan/common.c | 13 +++++++------ mm/slab.c | 15 +++++++++++---- mm/slub.c | 43 ++++++++++++++++++++++++------------------- 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index bb756f6c73b5..1df0f7f0b493 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -193,11 +193,13 @@ static __always_inline void * __must_check kasan_init_slab_obj( return (void *)object; } -bool __kasan_slab_free(struct kmem_cache *s, void *object, unsigned long ip); -static __always_inline bool kasan_slab_free(struct kmem_cache *s, void *object) +bool __kasan_slab_free(struct kmem_cache *s, void *object, + unsigned long ip, bool init); +static __always_inline bool kasan_slab_free(struct kmem_cache *s, + void *object, bool init) { if (kasan_enabled()) - return __kasan_slab_free(s, object, _RET_IP_); + return __kasan_slab_free(s, object, _RET_IP_, init); return false; } @@ -299,7 +301,7 @@ static inline void *kasan_init_slab_obj(struct kmem_cache *cache, { return (void *)object; } -static inline bool kasan_slab_free(struct kmem_cache *s, void *object) +static inline bool kasan_slab_free(struct kmem_cache *s, void *object, bool init) { return false; } diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 7ea747b18c26..623cf94288a2 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -322,8 +322,8 @@ void * __must_check __kasan_init_slab_obj(struct kmem_cache *cache, return (void *)object; } -static inline bool ____kasan_slab_free(struct kmem_cache *cache, - void *object, unsigned long ip, bool quarantine) +static inline bool ____kasan_slab_free(struct kmem_cache *cache, void *object, + unsigned long ip, bool quarantine, bool init) { u8 tag; void *tagged_object; @@ -351,7 +351,7 @@ static inline bool ____kasan_slab_free(struct kmem_cache *cache, } kasan_poison(object, round_up(cache->object_size, KASAN_GRANULE_SIZE), - KASAN_KMALLOC_FREE, false); + KASAN_KMALLOC_FREE, init); if ((IS_ENABLED(CONFIG_KASAN_GENERIC) && !quarantine)) return false; @@ -362,9 +362,10 @@ static inline bool ____kasan_slab_free(struct kmem_cache *cache, return kasan_quarantine_put(cache, object); } -bool __kasan_slab_free(struct kmem_cache *cache, void *object, unsigned long ip) +bool __kasan_slab_free(struct kmem_cache *cache, void *object, + unsigned long ip, bool init) { - return ____kasan_slab_free(cache, object, ip, true); + return ____kasan_slab_free(cache, object, ip, true, init); } static inline bool ____kasan_kfree_large(void *ptr, unsigned long ip) @@ -409,7 +410,7 @@ void __kasan_slab_free_mempool(void *ptr, unsigned long ip) return; kasan_poison(ptr, page_size(page), KASAN_FREE_PAGE, false); } else { - ____kasan_slab_free(page->slab_cache, ptr, ip, false); + ____kasan_slab_free(page->slab_cache, ptr, ip, false, false); } } diff --git a/mm/slab.c b/mm/slab.c index 936dd686dec9..d12ce9e5c3ed 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -3425,17 +3425,24 @@ static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac) static __always_inline void __cache_free(struct kmem_cache *cachep, void *objp, unsigned long caller) { + bool init; + if (is_kfence_address(objp)) { kmemleak_free_recursive(objp, cachep->flags); __kfence_free(objp); return; } - if (unlikely(slab_want_init_on_free(cachep))) + /* + * As memory initialization is integrated with hardware tag-based + * KASAN, kasan_slab_free and initialization memset must be + * kept together to avoid discrepancies in behavior. + */ + init = slab_want_init_on_free(cachep); + if (init && !IS_ENABLED(CONFIG_KASAN_HW_TAGS)) memset(objp, 0, cachep->object_size); - - /* Put the object into the quarantine, don't touch it for now. */ - if (kasan_slab_free(cachep, objp)) + /* KASAN might put objp into memory quarantine, delaying its reuse. */ + if (kasan_slab_free(cachep, objp, init)) return; /* Use KCSAN to help debug racy use-after-free. */ diff --git a/mm/slub.c b/mm/slub.c index f53df23760e3..c2755670d6bd 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1532,7 +1532,8 @@ static __always_inline void kfree_hook(void *x) kasan_kfree_large(x); } -static __always_inline bool slab_free_hook(struct kmem_cache *s, void *x) +static __always_inline bool slab_free_hook(struct kmem_cache *s, + void *x, bool init) { kmemleak_free_recursive(x, s->flags); @@ -1558,8 +1559,25 @@ static __always_inline bool slab_free_hook(struct kmem_cache *s, void *x) __kcsan_check_access(x, s->object_size, KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ASSERT); - /* KASAN might put x into memory quarantine, delaying its reuse */ - return kasan_slab_free(s, x); + /* + * As memory initialization is integrated with hardware tag-based + * KASAN, kasan_slab_free and initialization memset's must be + * kept together to avoid discrepancies in behavior. + * + * The initialization memset's clear the object and the metadata, + * but don't touch the SLAB redzone. + */ + if (init) { + int rsize; + + if (!IS_ENABLED(CONFIG_KASAN_HW_TAGS)) + memset(kasan_reset_tag(x), 0, s->object_size); + rsize = (s->flags & SLAB_RED_ZONE) ? s->red_left_pad : 0; + memset((char *)kasan_reset_tag(x) + s->inuse, 0, + s->size - s->inuse - rsize); + } + /* KASAN might put x into memory quarantine, delaying its reuse. */ + return kasan_slab_free(s, x, init); } static inline bool slab_free_freelist_hook(struct kmem_cache *s, @@ -1569,10 +1587,9 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, void *object; void *next = *head; void *old_tail = *tail ? *tail : *head; - int rsize; if (is_kfence_address(next)) { - slab_free_hook(s, next); + slab_free_hook(s, next, false); return true; } @@ -1584,20 +1601,8 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, object = next; next = get_freepointer(s, object); - if (slab_want_init_on_free(s)) { - /* - * Clear the object and the metadata, but don't touch - * the redzone. - */ - memset(kasan_reset_tag(object), 0, s->object_size); - rsize = (s->flags & SLAB_RED_ZONE) ? s->red_left_pad - : 0; - memset((char *)kasan_reset_tag(object) + s->inuse, 0, - s->size - s->inuse - rsize); - - } /* If object's reuse doesn't have to be delayed */ - if (!slab_free_hook(s, object)) { + if (!slab_free_hook(s, object, slab_want_init_on_free(s))) { /* Move object to the new freelist */ set_freepointer(s, object, *head); *head = object; @@ -3235,7 +3240,7 @@ int build_detached_freelist(struct kmem_cache *s, size_t size, } if (is_kfence_address(object)) { - slab_free_hook(df->s, object); + slab_free_hook(df->s, object, false); __kfence_free(object); p[size] = NULL; /* mark object processed */ return size; -- 2.30.1.766.gb4fecdf3b7-goog