From nobody Mon Dec 1 22:04:04 2025 Received: from localhost.localdomain (unknown [147.136.157.3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6BB5B23E325 for ; Fri, 28 Nov 2025 11:15:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=147.136.157.3 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764328538; cv=none; b=nKJV6DTUHuZ42tfZmIn5aDgyal3bWgafSWTimLS/3O5k3qsRFQC6GQUPsb9LpHE3+iDF8D5DZoE6q5HcJ5z4K+MutJG2dSenOEzZViLkHywMqOiXppsaytCs8aXKN3ybbyROLhq6v9uasWUtx34D4ah7inpZBH8aEenYRmH8tKk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764328538; c=relaxed/simple; bh=5w0Qmz7wG+3jFiGWWV7f3WjKcOJyarYxEGGdRpzYnVI=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type; b=Vs0OlsJIyZ/iLEckbLV7zjfQmChaRVcmLX66dOlkCzNdgP1lFtPVIEoGg7bxsO7uuKM/JP91L6NusZxk3mcP4l3PZLk6v/bffY0/hgpilHVMvKGX3sFQu0wrZz39NQ+YKrgLd151qZivbgZFR9cpBPm6MMbf4xHPZkuYYBK9pq8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.dev; spf=none smtp.mailfrom=localhost.localdomain; arc=none smtp.client-ip=147.136.157.3 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=localhost.localdomain Received: by localhost.localdomain (Postfix, from userid 1007) id 43CD28B2A2A; Fri, 28 Nov 2025 19:15:29 +0800 (+08) From: Jiayuan Chen To: linux-mm@kvack.org Cc: Jiayuan Chen , syzbot+997752115a851cb0cf36@syzkaller.appspotmail.com, Andrey Ryabinin , Alexander Potapenko , Andrey Konovalov , Dmitry Vyukov , Vincenzo Frascino , Andrew Morton , Uladzislau Rezki , Danilo Krummrich , Kees Cook , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org Subject: [PATCH v1] mm/kasan: Fix incorrect unpoisoning in vrealloc for KASAN Date: Fri, 28 Nov 2025 19:15:14 +0800 Message-ID: <20251128111516.244497-1-jiayuan.chen@linux.dev> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Syzkaller reported a memory out-of-bounds bug [1]. This patch fixes two issues: 1. In vrealloc, we were missing the KASAN_VMALLOC_VM_ALLOC flag when unpoisoning the extended region. This flag is required to correctly associate the allocation with KASAN's vmalloc tracking. Note: In contrast, vzalloc (via __vmalloc_node_range_noprof) explicitly sets KASAN_VMALLOC_VM_ALLOC and calls kasan_unpoison_vmalloc() with it. vrealloc must behave consistently =E2=80=94 especially when reusing exis= ting vmalloc regions =E2=80=94 to ensure KASAN can track allocations correctl= y. 2. When vrealloc reuses an existing vmalloc region (without allocating new pages), KASAN previously generated a new tag, which broke tag-based memory access tracking. We now add a 'reuse_tag' parameter to __kasan_unpoison_vmalloc() to preserve the original tag in such cases. A new helper kasan_unpoison_vralloc() is introduced to handle this reuse scenario, ensuring consistent tag behavior during reallocation. [1]: https://syzkaller.appspot.com/bug?extid=3D997752115a851cb0cf36 Fixes: a0309faf1cb0 ("mm: vmalloc: support more granular vrealloc() sizing") Reported-by: syzbot+997752115a851cb0cf36@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/68e243a2.050a0220.1696c6.007d.GAE@googl= e.com/T/ Signed-off-by: Jiayuan Chen --- include/linux/kasan.h | 21 +++++++++++++++++++-- mm/kasan/hw_tags.c | 4 ++-- mm/kasan/shadow.c | 6 ++++-- mm/vmalloc.c | 4 ++-- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/include/linux/kasan.h b/include/linux/kasan.h index f335c1d7b61d..14e59e898c29 100644 --- a/include/linux/kasan.h +++ b/include/linux/kasan.h @@ -612,13 +612,23 @@ static inline void kasan_release_vmalloc(unsigned lon= g start, #endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */ =20 void *__kasan_unpoison_vmalloc(const void *start, unsigned long size, - kasan_vmalloc_flags_t flags); + kasan_vmalloc_flags_t flags, bool reuse_tag); + +static __always_inline void *kasan_unpoison_vrealloc(const void *start, + unsigned long size, + kasan_vmalloc_flags_t flags) +{ + if (kasan_enabled()) + return __kasan_unpoison_vmalloc(start, size, flags, true); + return (void *)start; +} + static __always_inline void *kasan_unpoison_vmalloc(const void *start, unsigned long size, kasan_vmalloc_flags_t flags) { if (kasan_enabled()) - return __kasan_unpoison_vmalloc(start, size, flags); + return __kasan_unpoison_vmalloc(start, size, flags, false); return (void *)start; } =20 @@ -645,6 +655,13 @@ static inline void kasan_release_vmalloc(unsigned long= start, unsigned long free_region_end, unsigned long flags) { } =20 +static inline void *kasan_unpoison_vrealloc(const void *start, + unsigned long size, + kasan_vmalloc_flags_t flags) +{ + return (void *)start; +} + static inline void *kasan_unpoison_vmalloc(const void *start, unsigned long size, kasan_vmalloc_flags_t flags) diff --git a/mm/kasan/hw_tags.c b/mm/kasan/hw_tags.c index 1c373cc4b3fa..04a62ac27165 100644 --- a/mm/kasan/hw_tags.c +++ b/mm/kasan/hw_tags.c @@ -317,7 +317,7 @@ static void init_vmalloc_pages(const void *start, unsig= ned long size) } =20 void *__kasan_unpoison_vmalloc(const void *start, unsigned long size, - kasan_vmalloc_flags_t flags) + kasan_vmalloc_flags_t flags, bool reuse_tag) { u8 tag; unsigned long redzone_start, redzone_size; @@ -361,7 +361,7 @@ void *__kasan_unpoison_vmalloc(const void *start, unsig= ned long size, return (void *)start; } =20 - tag =3D kasan_random_tag(); + tag =3D reuse_tag ? get_tag(start) : kasan_random_tag(); start =3D set_tag(start, tag); =20 /* Unpoison and initialize memory up to size. */ diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c index 29a751a8a08d..354842c7f927 100644 --- a/mm/kasan/shadow.c +++ b/mm/kasan/shadow.c @@ -611,7 +611,7 @@ void __kasan_release_vmalloc(unsigned long start, unsig= ned long end, } =20 void *__kasan_unpoison_vmalloc(const void *start, unsigned long size, - kasan_vmalloc_flags_t flags) + kasan_vmalloc_flags_t flags, bool reuse_tag) { /* * Software KASAN modes unpoison both VM_ALLOC and non-VM_ALLOC @@ -631,7 +631,9 @@ void *__kasan_unpoison_vmalloc(const void *start, unsig= ned long size, !(flags & KASAN_VMALLOC_PROT_NORMAL)) return (void *)start; =20 - start =3D set_tag(start, kasan_random_tag()); + if (!reuse_tag) + start =3D set_tag(start, kasan_random_tag()); + kasan_unpoison(start, size, false); return (void *)start; } diff --git a/mm/vmalloc.c b/mm/vmalloc.c index ecbac900c35f..1ddd6ffc89c1 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -4330,8 +4330,8 @@ void *vrealloc_node_align_noprof(const void *p, size_= t size, unsigned long align * We already have the bytes available in the allocation; use them. */ if (size <=3D alloced_size) { - kasan_unpoison_vmalloc(p + old_size, size - old_size, - KASAN_VMALLOC_PROT_NORMAL); + kasan_unpoison_vrealloc(p, size, + KASAN_VMALLOC_PROT_NORMAL | KASAN_VMALLOC_VM_ALLOC); /* * No need to zero memory here, as unused memory will have * already been zeroed at initial allocation time or during --=20 2.43.0