From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id C36C9C4321E for ; Tue, 23 Nov 2021 14:21:40 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 3FC456B006C; Tue, 23 Nov 2021 09:21:25 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 3ACD86B0073; Tue, 23 Nov 2021 09:21:25 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 272866B0074; Tue, 23 Nov 2021 09:21:25 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0144.hostedemail.com [216.40.44.144]) by kanga.kvack.org (Postfix) with ESMTP id 19B106B006C for ; Tue, 23 Nov 2021 09:21:25 -0500 (EST) Received: from smtpin02.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay03.hostedemail.com (Postfix) with ESMTP id CD921824C449 for ; Tue, 23 Nov 2021 14:21:14 +0000 (UTC) X-FDA: 78840407268.02.33FF855 Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by imf05.hostedemail.com (Postfix) with ESMTP id 674FE508BD49 for ; Tue, 23 Nov 2021 14:21:07 +0000 (UTC) Received: from dggpemm500020.china.huawei.com (unknown [172.30.72.57]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4Hz5s651Lhz90r9; Tue, 23 Nov 2021 22:20:42 +0800 (CST) Received: from dggpemm500001.china.huawei.com (7.185.36.107) by dggpemm500020.china.huawei.com (7.185.36.49) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.20; Tue, 23 Nov 2021 22:21:08 +0800 Received: from localhost.localdomain.localdomain (10.175.113.25) by dggpemm500001.china.huawei.com (7.185.36.107) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2308.20; Tue, 23 Nov 2021 22:21:07 +0800 From: Kefeng Wang To: Andrey Ryabinin , Dmitry Vyukov , Andrew Morton , , , , , CC: Catalin Marinas , Will Deacon , Heiko Carstens , Vasily Gorbik , Christian Borntraeger , Alexander Gordeev , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , Alexander Potapenko , Kefeng Wang , Yongqiang Liu Subject: [PATCH v2] mm: Delay kmemleak object creation of module_alloc() Date: Tue, 23 Nov 2021 22:32:20 +0800 Message-ID: <20211123143220.134361-1-wangkefeng.wang@huawei.com> X-Mailer: git-send-email 2.26.2 MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.175.113.25] X-ClientProxiedBy: dggems704-chm.china.huawei.com (10.3.19.181) To dggpemm500001.china.huawei.com (7.185.36.107) X-CFilter-Loop: Reflected X-Rspamd-Server: rspam01 X-Rspamd-Queue-Id: 674FE508BD49 X-Stat-Signature: ekmtyx3kymipgfkp8isykhckwi18m6ct Authentication-Results: imf05.hostedemail.com; dkim=none; dmarc=pass (policy=quarantine) header.from=huawei.com; spf=pass (imf05.hostedemail.com: domain of wangkefeng.wang@huawei.com designates 45.249.212.188 as permitted sender) smtp.mailfrom=wangkefeng.wang@huawei.com X-HE-Tag: 1637677267-843900 Content-Transfer-Encoding: quoted-printable X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: Yongqiang reports a kmemleak panic when module insmod/rmmod with KASAN enabled on x86[1]. When the module allocates memory, it's kmemleak_object is created success= fully, but the KASAN shadow memory of module allocation is not ready, so when km= emleak scan the module's pointer, it will panic due to no shadow memory with KAS= AN. module_alloc __vmalloc_node_range kmemleak_vmalloc kmemleak_scan update_checksum kasan_module_alloc kmemleak_ignore The bug should exist on ARM64/S390 too, add a VM_DELAY_KMEMLEAK flags, de= lay vmalloc'ed object register of kmemleak in module_alloc(). [1] https://lore.kernel.org/all/6d41e2b9-4692-5ec4-b1cd-cbe29ae89739@huaw= ei.com/ Reported-by: Yongqiang Liu Signed-off-by: Kefeng Wang --- v2: - fix type error on changelog and kasan_module_alloc() arch/arm64/kernel/module.c | 4 ++-- arch/s390/kernel/module.c | 5 +++-- arch/x86/kernel/module.c | 7 ++++--- include/linux/kasan.h | 4 ++-- include/linux/vmalloc.h | 7 +++++++ mm/kasan/shadow.c | 9 +++++++-- mm/vmalloc.c | 3 ++- 7 files changed, 27 insertions(+), 12 deletions(-) diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index b5ec010c481f..e6da010716d0 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -36,7 +36,7 @@ void *module_alloc(unsigned long size) module_alloc_end =3D MODULES_END; =20 p =3D __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base, - module_alloc_end, gfp_mask, PAGE_KERNEL, 0, + module_alloc_end, gfp_mask, PAGE_KERNEL, VM_DELAY_KMEMLEAK, NUMA_NO_NODE, __builtin_return_address(0)); =20 if (!p && IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) && @@ -58,7 +58,7 @@ void *module_alloc(unsigned long size) PAGE_KERNEL, 0, NUMA_NO_NODE, __builtin_return_address(0)); =20 - if (p && (kasan_module_alloc(p, size) < 0)) { + if (p && (kasan_module_alloc(p, size, gfp_mask) < 0)) { vfree(p); return NULL; } diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index b01ba460b7ca..8d66a93562ca 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -37,14 +37,15 @@ =20 void *module_alloc(unsigned long size) { + gfp_t gfp_mask =3D GFP_KERNEL; void *p; =20 if (PAGE_ALIGN(size) > MODULES_LEN) return NULL; p =3D __vmalloc_node_range(size, MODULE_ALIGN, MODULES_VADDR, MODULES_E= ND, - GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, + gfp_mask, PAGE_KERNEL_EXEC, VM_DELAY_KMEMLEAK, NUMA_NO_NODE, __builtin_return_address(0)); - if (p && (kasan_module_alloc(p, size) < 0)) { + if (p && (kasan_module_alloc(p, size, gfp_mask) < 0)) { vfree(p); return NULL; } diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index 169fb6f4cd2e..ff134d0f1ca1 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -67,6 +67,7 @@ static unsigned long int get_module_load_offset(void) =20 void *module_alloc(unsigned long size) { + gfp_t gfp_mask =3D GFP_KERNEL; void *p; =20 if (PAGE_ALIGN(size) > MODULES_LEN) @@ -74,10 +75,10 @@ void *module_alloc(unsigned long size) =20 p =3D __vmalloc_node_range(size, MODULE_ALIGN, MODULES_VADDR + get_module_load_offset(), - MODULES_END, GFP_KERNEL, - PAGE_KERNEL, 0, NUMA_NO_NODE, + MODULES_END, gfp_mask, + PAGE_KERNEL, VM_DELAY_KMEMLEAK, NUMA_NO_NODE, __builtin_return_address(0)); - if (p && (kasan_module_alloc(p, size) < 0)) { + if (p && (kasan_module_alloc(p, size, gfp_mask) < 0)) { vfree(p); return NULL; } diff --git a/include/linux/kasan.h b/include/linux/kasan.h index d8783b682669..89c99e5e67de 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -474,12 +474,12 @@ static inline void kasan_populate_early_vm_area_sha= dow(void *start, * allocations with real shadow memory. With KASAN vmalloc, the special * case is unnecessary, as the work is handled in the generic case. */ -int kasan_module_alloc(void *addr, size_t size); +int kasan_module_alloc(void *addr, size_t size, gfp_t gfp_mask); void kasan_free_shadow(const struct vm_struct *vm); =20 #else /* (CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS) && !CONFIG_KASAN= _VMALLOC */ =20 -static inline int kasan_module_alloc(void *addr, size_t size) { return 0= ; } +static inline int kasan_module_alloc(void *addr, size_t size, gfp_t gfp_= mask) { return 0; } static inline void kasan_free_shadow(const struct vm_struct *vm) {} =20 #endif /* (CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS) && !CONFIG_KASA= N_VMALLOC */ diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 6e022cc712e6..56d2b7828b31 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -28,6 +28,13 @@ struct notifier_block; /* in notifier.h */ #define VM_MAP_PUT_PAGES 0x00000200 /* put pages and free array in vfree= */ #define VM_NO_HUGE_VMAP 0x00000400 /* force PAGE_SIZE pte mapping */ =20 +#if defined(CONFIG_KASAN) && (defined(CONFIG_KASAN_GENERIC) || \ + defined(CONFIG_KASAN_SW_TAGS)) && !defined(CONFIG_KASAN_VMALLOC) +#define VM_DELAY_KMEMLEAK 0x00000800 /* delay kmemleak object create */ +#else +#define VM_DELAY_KMEMLEAK 0 +#endif + /* * VM_KASAN is used slightly differently depending on CONFIG_KASAN_VMALL= OC. * diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c index 4a4929b29a23..2ade2f484562 100644 --- a/mm/kasan/shadow.c +++ b/mm/kasan/shadow.c @@ -498,7 +498,7 @@ void kasan_release_vmalloc(unsigned long start, unsig= ned long end, =20 #else /* CONFIG_KASAN_VMALLOC */ =20 -int kasan_module_alloc(void *addr, size_t size) +int kasan_module_alloc(void *addr, size_t size, gfp_t gfp_mask) { void *ret; size_t scaled_size; @@ -520,9 +520,14 @@ int kasan_module_alloc(void *addr, size_t size) __builtin_return_address(0)); =20 if (ret) { + struct vm_struct *vm =3D find_vm_area(addr); __memset(ret, KASAN_SHADOW_INIT, shadow_size); - find_vm_area(addr)->flags |=3D VM_KASAN; + vm->flags |=3D VM_KASAN; kmemleak_ignore(ret); + + if (vm->flags & VM_DELAY_KMEMLEAK) + kmemleak_vmalloc(vm, size, gfp_mask); + return 0; } =20 diff --git a/mm/vmalloc.c b/mm/vmalloc.c index d2a00ad4e1dd..23c595b15839 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -3074,7 +3074,8 @@ void *__vmalloc_node_range(unsigned long size, unsi= gned long align, clear_vm_uninitialized_flag(area); =20 size =3D PAGE_ALIGN(size); - kmemleak_vmalloc(area, size, gfp_mask); + if (!(vm_flags & VM_DELAY_KMEMLEAK)) + kmemleak_vmalloc(area, size, gfp_mask); =20 return addr; =20 --=20 2.27.0