Received: by 2002:a25:7ec1:0:0:0:0:0 with SMTP id z184csp8259617ybc; Fri, 29 Nov 2019 07:46:59 -0800 (PST) X-Google-Smtp-Source: APXvYqzkTc/EK8FKLpgl8UzwphGQOq+kSVdiaqnI8yhZMH3YjQkFMnTGPhUFzi16ZCFX6QGiUlz4 X-Received: by 2002:a05:6402:19ae:: with SMTP id o14mr47148610edz.241.1575042419075; Fri, 29 Nov 2019 07:46:59 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1575042419; cv=none; d=google.com; s=arc-20160816; b=SDTHO8QLbA8cLPPbKKCVk+4JHw56UB2mKMuWxnitakKdK1+RM2P03EvLzH+wEXMN8l Q7QJGeXvdVUMGotw7OmGmrtvvd8e7/dEeQ3UdXIfn75llYL3hhd7CODLtdHXJnwCYGL6 r/k6SsQKXmed+OL4n0DZZu4fplJMSC/94roVx1G7VXbN9GkCm7HbaS6YV9wA3Igb0Bi9 sG3UDpu4me7Dh5rKR5Ut6zcXHl715plFS5lbJ2vraDdpiJMPUu0mFLhMiaVhyYh9juMs EjKapTLITjzxzUbjtWnszzp/h1sQ7h0OnFYPTTEb9XYfIsRcTV2o8EjZpVLvi+HR4d1A Zryg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=vsKvBmcEHkBcKrbZ7FMQtODXsXcFjKXnby3n743Jem8=; b=qeswuXGgwLdZn2QCqFMXJGzgb70/JHqEjKSyslhK93NDN+Cl+WuAjCNAlT4REZtW+b OfqV3kaBZxubkEo3yKZ+zsxhwjP1/Yah+XGgLtP7Fxm4NZx7n6oK2WAA4+cKZNAPTejX gewEDDOesnDIelNncLdJ1X+MueEIaWRlVEZe6WOL0BVXZy7IvZX4hKXhETTGO7E+f0wA +yub4qPF+9z3EEtRComNLuk17xsfJMHl+0uttxSf7VrgfQHiMMUWHpgBu0SS0ESZ3SzS yvhYqJx46I3GfXVaRArOxYM3SzB7rtNWE9+rWqrshTWI6hkwgf/+hfaLHyllhByZ2C1p Ejxg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@axtens.net header.s=google header.b=eRxKLAUk; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l10si14623583ejb.336.2019.11.29.07.46.34; Fri, 29 Nov 2019 07:46:59 -0800 (PST) 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=@axtens.net header.s=google header.b=eRxKLAUk; 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726985AbfK2Pp2 (ORCPT + 99 others); Fri, 29 Nov 2019 10:45:28 -0500 Received: from mail-pj1-f65.google.com ([209.85.216.65]:39712 "EHLO mail-pj1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726808AbfK2Pp2 (ORCPT ); Fri, 29 Nov 2019 10:45:28 -0500 Received: by mail-pj1-f65.google.com with SMTP id v93so10149738pjb.6 for ; Fri, 29 Nov 2019 07:45:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=axtens.net; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=vsKvBmcEHkBcKrbZ7FMQtODXsXcFjKXnby3n743Jem8=; b=eRxKLAUkQ7j0Crv9q/2f0pvf4D4ZeeIFIFgK9WXy7RBTxfbRWQAZBKqifEEv6c9b9/ OIrFQy+q6JbAX6Byz9AeHc/gopoSqZRzKkd3hAKj7k0+bKg9n6mDzsJFZu67N+GTd8BI +Fb4/RI78bHBGxV0B0dXbSRQm1/9KX6McwbUM= 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:mime-version :content-transfer-encoding; bh=vsKvBmcEHkBcKrbZ7FMQtODXsXcFjKXnby3n743Jem8=; b=EdwzaXXkKMTa3vMLurEpZutiDexE1Ws0nrrUFf7ErekcLl+dOoNld+SzPcCK6J36S2 qBadsUYxkwW5l98mi6volpKCifpHhJv6H1m/ayfpcj9klFlEMikttALX3qyfKIxvoNlA /mEgbjKrRPqjbIn3GrghOWDfLzN5oPPhzVx+p8AKVh5Trl2mJ6qoyc5si+NoLVdIKu9T 7uje2Ec+7MYP+Sam494cn/M+u0g1+OAbdZjFap7qp/J/0QRDgXun4KFWqlWWNE1EmiDf ikm9W2aH+zzwIDFhvJMlXqMUfWlIw1jB/Aelz2tdYjYTSvUZMWO1rRLEfOM1LTDBEyWU 24rA== X-Gm-Message-State: APjAAAUltSYOYtBpk4Acixvenn/z2YWHYfCR24fPOJK0uaQT62XO/hrf ST+ROtzAEIO0UCdqq1HMR7R3tw== X-Received: by 2002:a17:902:968b:: with SMTP id n11mr8143652plp.120.1575042325924; Fri, 29 Nov 2019 07:45:25 -0800 (PST) Received: from localhost (2001-44b8-111e-5c00-4092-39f5-bb9d-b59a.static.ipv6.internode.on.net. [2001:44b8:111e:5c00:4092:39f5:bb9d:b59a]) by smtp.gmail.com with ESMTPSA id 186sm25273018pfe.141.2019.11.29.07.45.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 29 Nov 2019 07:45:25 -0800 (PST) From: Daniel Axtens To: kasan-dev@googlegroups.com, linux-mm@kvack.org, x86@kernel.org, aryabinin@virtuozzo.com, glider@google.com, linux-kernel@vger.kernel.org, dvyukov@google.com Cc: Daniel Axtens , Qian Cai Subject: [PATCH] kasan: support vmalloc backing of vm_map_ram() Date: Sat, 30 Nov 2019 02:45:19 +1100 Message-Id: <20191129154519.30964-1-dja@axtens.net> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This fixes some crashes in xfs, binder and the i915 mock_selftests, with kasan vmalloc, where no shadow space was being allocated when vm_map_ram was called. vm_map_ram has two paths, a path that uses vmap_block and a path that uses alloc_vmap_area. The alloc_vmap_area path is straight-forward, we handle it like most other allocations. For the vmap_block case, we map a shadow for the entire vmap_block when the block is allocated, and unpoison it piecewise in vm_map_ram(). It already gets cleaned up when the block is released in the lazy vmap area freeing path. For both cases, we need to tweak the interface to allow for vmalloc addresses that don't have an attached vm_struct. Reported-by: Dmitry Vyukov Cc: Qian Cai Thanks-to: Andrey Ryabinin Signed-off-by: Daniel Axtens --- include/linux/kasan.h | 6 ++++++ mm/kasan/common.c | 37 +++++++++++++++++++++++-------------- mm/vmalloc.c | 24 ++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index 4f404c565db1..0b50b59a8ff5 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -207,6 +207,7 @@ static inline void *kasan_reset_tag(const void *addr) #ifdef CONFIG_KASAN_VMALLOC int kasan_populate_vmalloc(unsigned long requested_size, struct vm_struct *area); +int kasan_populate_vmalloc_area(unsigned long size, void *addr); void kasan_poison_vmalloc(void *start, unsigned long size); void kasan_release_vmalloc(unsigned long start, unsigned long end, unsigned long free_region_start, @@ -218,6 +219,11 @@ static inline int kasan_populate_vmalloc(unsigned long requested_size, return 0; } +static inline int kasan_populate_vmalloc_area(unsigned long size, void *addr) +{ + return 0; +} + static inline void kasan_poison_vmalloc(void *start, unsigned long size) {} static inline void kasan_release_vmalloc(unsigned long start, unsigned long end, diff --git a/mm/kasan/common.c b/mm/kasan/common.c index df3371d5c572..27d8522ffaad 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -779,27 +779,15 @@ static int kasan_populate_vmalloc_pte(pte_t *ptep, unsigned long addr, int kasan_populate_vmalloc(unsigned long requested_size, struct vm_struct *area) { - unsigned long shadow_start, shadow_end; int ret; - - shadow_start = (unsigned long)kasan_mem_to_shadow(area->addr); - shadow_start = ALIGN_DOWN(shadow_start, PAGE_SIZE); - shadow_end = (unsigned long)kasan_mem_to_shadow(area->addr + - area->size); - shadow_end = ALIGN(shadow_end, PAGE_SIZE); - - ret = apply_to_page_range(&init_mm, shadow_start, - shadow_end - shadow_start, - kasan_populate_vmalloc_pte, NULL); + ret = kasan_populate_vmalloc_area(area->size, area->addr); if (ret) return ret; - flush_cache_vmap(shadow_start, shadow_end); + area->flags |= VM_KASAN; kasan_unpoison_shadow(area->addr, requested_size); - area->flags |= VM_KASAN; - /* * We need to be careful about inter-cpu effects here. Consider: * @@ -838,6 +826,27 @@ int kasan_populate_vmalloc(unsigned long requested_size, struct vm_struct *area) return 0; } +int kasan_populate_vmalloc_area(unsigned long size, void *addr) +{ + unsigned long shadow_start, shadow_end; + int ret; + + shadow_start = (unsigned long)kasan_mem_to_shadow(addr); + shadow_start = ALIGN_DOWN(shadow_start, PAGE_SIZE); + shadow_end = (unsigned long)kasan_mem_to_shadow(addr + size); + shadow_end = ALIGN(shadow_end, PAGE_SIZE); + + ret = apply_to_page_range(&init_mm, shadow_start, + shadow_end - shadow_start, + kasan_populate_vmalloc_pte, NULL); + if (ret) + return ret; + + flush_cache_vmap(shadow_start, shadow_end); + + return 0; +} + /* * Poison the shadow for a vmalloc region. Called as part of the * freeing process at the time the region is freed. diff --git a/mm/vmalloc.c b/mm/vmalloc.c index bf030516258c..2896189e351f 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -1509,6 +1509,13 @@ static void *new_vmap_block(unsigned int order, gfp_t gfp_mask) return ERR_CAST(va); } + err = kasan_populate_vmalloc_area(VMAP_BLOCK_SIZE, va->va_start); + if (unlikely(err)) { + kfree(vb); + free_vmap_area(va); + return ERR_PTR(err); + } + err = radix_tree_preload(gfp_mask); if (unlikely(err)) { kfree(vb); @@ -1554,6 +1561,7 @@ static void free_vmap_block(struct vmap_block *vb) spin_unlock(&vmap_block_tree_lock); BUG_ON(tmp != vb); + /* free_vmap_area will take care of freeing the shadow */ free_vmap_area_noflush(vb->va); kfree_rcu(vb, rcu_head); } @@ -1780,6 +1788,8 @@ void vm_unmap_ram(const void *mem, unsigned int count) if (likely(count <= VMAP_MAX_ALLOC)) { debug_check_no_locks_freed(mem, size); vb_free(mem, size); + kasan_poison_vmalloc(mem, size); + return; } @@ -1787,6 +1797,7 @@ void vm_unmap_ram(const void *mem, unsigned int count) BUG_ON(!va); debug_check_no_locks_freed((void *)va->va_start, (va->va_end - va->va_start)); + /* vmap area purging will clean up the KASAN shadow later */ free_unmap_vmap_area(va); } EXPORT_SYMBOL(vm_unmap_ram); @@ -1817,6 +1828,11 @@ void *vm_map_ram(struct page **pages, unsigned int count, int node, pgprot_t pro if (IS_ERR(mem)) return NULL; addr = (unsigned long)mem; + + /* + * We don't need to call kasan_populate_vmalloc_area here, as + * it's done at block allocation time. + */ } else { struct vmap_area *va; va = alloc_vmap_area(size, PAGE_SIZE, @@ -1826,7 +1842,15 @@ void *vm_map_ram(struct page **pages, unsigned int count, int node, pgprot_t pro addr = va->va_start; mem = (void *)addr; + + if (kasan_populate_vmalloc_area(size, mem)) { + vm_unmap_ram(mem, count); + return NULL; + } } + + kasan_unpoison_shadow(mem, size); + if (vmap_page_range(addr, addr + size, prot, pages) < 0) { vm_unmap_ram(mem, count); return NULL; -- 2.20.1