* Re: [PATCH v1] mm/kasan: Fix incorrect unpoisoning in vrealloc for KASAN
[not found] <20251128111516.244497-1-jiayuan.chen@linux.dev>
@ 2025-12-02 20:48 ` Maciej Wieczor-Retman
2025-12-03 2:05 ` Jiayuan Chen
2025-12-02 23:23 ` Kees Cook
1 sibling, 1 reply; 10+ messages in thread
From: Maciej Wieczor-Retman @ 2025-12-02 20:48 UTC (permalink / raw)
To: Jiayuan Chen
Cc: linux-mm, syzbot+997752115a851cb0cf36, Andrey Ryabinin,
Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
Vincenzo Frascino, Andrew Morton, Uladzislau Rezki,
Danilo Krummrich, Kees Cook, kasan-dev, linux-kernel
Hi, I'm working on [1]. As Andrew pointed out to me the patches are quite
similar. I was wondering if you mind if the reuse_tag was an actual tag value?
Instead of just bool toggling the usage of kasan_random_tag()?
I tested the problem I'm seeing, with your patch and the tags end up being reset.
That's because the vms[area] pointers that I want to unpoison don't have a tag
set, but generating a different random tag for each vms[] pointer crashes the
kernel down the line. So __kasan_unpoison_vmalloc() needs to be called on each
one but with the same tag.
Arguably I noticed my series also just resets the tags right now, but I'm
working to correct it at the moment. I can send a fixed version tomorrow. Just
wanted to ask if having __kasan_unpoison_vmalloc() set an actual predefined tag
is a problem from your point of view?
[1] https://lore.kernel.org/all/cover.1764685296.git.m.wieczorretman@pm.me/
On 2025-11-28 at 19:15:14 +0800, Jiayuan Chen wrote:
>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 — especially when reusing existing
> vmalloc regions — to ensure KASAN can track allocations correctly.
>
>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=997752115a851cb0cf36
>
>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@google.com/T/
>
>Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
>---
> 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 long start,
> #endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */
>
> 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;
> }
>
>@@ -645,6 +655,13 @@ static inline void kasan_release_vmalloc(unsigned long start,
> unsigned long free_region_end,
> unsigned long flags) { }
>
>+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, unsigned long size)
> }
>
> 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, unsigned long size,
> return (void *)start;
> }
>
>- tag = kasan_random_tag();
>+ tag = reuse_tag ? get_tag(start) : kasan_random_tag();
> start = set_tag(start, tag);
>
> /* 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, unsigned long end,
> }
>
> 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, unsigned long size,
> !(flags & KASAN_VMALLOC_PROT_NORMAL))
> return (void *)start;
>
>- start = set_tag(start, kasan_random_tag());
>+ if (!reuse_tag)
>+ start = 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 <= 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
>--
>2.43.0
>
--
Kind regards
Maciej Wieczór-Retman
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v1] mm/kasan: Fix incorrect unpoisoning in vrealloc for KASAN
[not found] <20251128111516.244497-1-jiayuan.chen@linux.dev>
2025-12-02 20:48 ` [PATCH v1] mm/kasan: Fix incorrect unpoisoning in vrealloc for KASAN Maciej Wieczor-Retman
@ 2025-12-02 23:23 ` Kees Cook
2025-12-03 1:29 ` Jiayuan Chen
1 sibling, 1 reply; 10+ messages in thread
From: Kees Cook @ 2025-12-02 23:23 UTC (permalink / raw)
To: Jiayuan Chen
Cc: linux-mm, syzbot+997752115a851cb0cf36, Andrey Ryabinin,
Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
Vincenzo Frascino, Andrew Morton, Uladzislau Rezki,
Danilo Krummrich, kasan-dev, linux-kernel
On Fri, Nov 28, 2025 at 07:15:14PM +0800, Jiayuan Chen wrote:
> 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 — especially when reusing existing
> vmalloc regions — to ensure KASAN can track allocations correctly.
>
> 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=997752115a851cb0cf36
>
> Fixes: a0309faf1cb0 ("mm: vmalloc: support more granular vrealloc() sizing")
Is this the right Fixes tag? I didn't change the kasan logic meaningfully
in the above patch, perhaps it should be commit d699440f58ce ("mm:
fix vrealloc()'s KASAN poisoning logic")
--
Kees Cook
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v1] mm/kasan: Fix incorrect unpoisoning in vrealloc for KASAN
2025-12-02 23:23 ` Kees Cook
@ 2025-12-03 1:29 ` Jiayuan Chen
0 siblings, 0 replies; 10+ messages in thread
From: Jiayuan Chen @ 2025-12-03 1:29 UTC (permalink / raw)
To: Kees Cook
Cc: linux-mm, syzbot+997752115a851cb0cf36, Andrey Ryabinin,
Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
Vincenzo Frascino, Andrew Morton, Uladzislau Rezki,
Danilo Krummrich, kasan-dev, linux-kernel
2025/12/3 07:23, "Kees Cook" <kees@kernel.org mailto:kees@kernel.org?to=%22Kees%20Cook%22%20%3Ckees%40kernel.org%3E > wrote:
>
> On Fri, Nov 28, 2025 at 07:15:14PM +0800, Jiayuan Chen wrote:
>
> >
> > 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 — especially when reusing existing
> > vmalloc regions — to ensure KASAN can track allocations correctly.
> >
> > 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=997752115a851cb0cf36
> >
> > Fixes: a0309faf1cb0 ("mm: vmalloc: support more granular vrealloc() sizing")
> >
> Is this the right Fixes tag? I didn't change the kasan logic meaningfully
> in the above patch, perhaps it should be commit d699440f58ce ("mm:
> fix vrealloc()'s KASAN poisoning logic")
The tag you provide is about shrinking but the issue I encountered was about
expanding(Grow the vm_area) and kasan_unpoison_vmalloc() didn't work well with expanding.
Thanks.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v1] mm/kasan: Fix incorrect unpoisoning in vrealloc for KASAN
2025-12-02 20:48 ` [PATCH v1] mm/kasan: Fix incorrect unpoisoning in vrealloc for KASAN Maciej Wieczor-Retman
@ 2025-12-03 2:05 ` Jiayuan Chen
0 siblings, 0 replies; 10+ messages in thread
From: Jiayuan Chen @ 2025-12-03 2:05 UTC (permalink / raw)
To: Maciej Wieczor-Retman
Cc: linux-mm, syzbot+997752115a851cb0cf36, Andrey Ryabinin,
Alexander Potapenko, Andrey Konovalov, Dmitry Vyukov,
Vincenzo Frascino, Andrew Morton, Uladzislau Rezki,
Danilo Krummrich, Kees Cook, kasan-dev, linux-kernel
December 3, 2025 at 04:48, "Maciej Wieczor-Retman" <maciej.wieczor-retman@intel.com mailto:maciej.wieczor-retman@intel.com?to=%22Maciej%20Wieczor-Retman%22%20%3Cmaciej.wieczor-retman%40intel.com%3E > wrote:
>
> Hi, I'm working on [1]. As Andrew pointed out to me the patches are quite
> similar. I was wondering if you mind if the reuse_tag was an actual tag value?
> Instead of just bool toggling the usage of kasan_random_tag()?
>
> I tested the problem I'm seeing, with your patch and the tags end up being reset.
> That's because the vms[area] pointers that I want to unpoison don't have a tag
> set, but generating a different random tag for each vms[] pointer crashes the
> kernel down the line. So __kasan_unpoison_vmalloc() needs to be called on each
> one but with the same tag.
>
> Arguably I noticed my series also just resets the tags right now, but I'm
> working to correct it at the moment. I can send a fixed version tomorrow. Just
> wanted to ask if having __kasan_unpoison_vmalloc() set an actual predefined tag
> is a problem from your point of view?
>
> [1] https://lore.kernel.org/all/cover.1764685296.git.m.wieczorretman@pm.me/
>
Hi Maciej,
It seems we're focusing on different issues, but feel free to reuse or modify the 'reuse_tag'.
It's intended to preserve the tag in one 'vma'.
I'd also be happy to help reproduce and test your changes to ensure the issue I encountered
isn't regressed once you send a patch based on mine.
Thanks.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v1] mm/kasan: Fix incorrect unpoisoning in vrealloc for KASAN
2025-12-04 15:06 ` Andrey Konovalov
@ 2025-12-04 15:35 ` Jiayuan Chen
0 siblings, 0 replies; 10+ messages in thread
From: Jiayuan Chen @ 2025-12-04 15:35 UTC (permalink / raw)
To: Andrey Konovalov
Cc: Maciej Wieczor-Retman, Maciej Wieczor-Retman, linux-mm,
syzbot+997752115a851cb0cf36, Andrey Ryabinin,
Alexander Potapenko, Dmitry Vyukov, Vincenzo Frascino,
Andrew Morton, Uladzislau Rezki, Danilo Krummrich, Kees Cook,
kasan-dev, linux-kernel
December 4, 2025 at 23:06, "Andrey Konovalov" <andreyknvl@gmail.com mailto:andreyknvl@gmail.com?to=%22Andrey%20Konovalov%22%20%3Candreyknvl%40gmail.com%3E > wrote:
>
> On Thu, Dec 4, 2025 at 3:38 PM Jiayuan Chen <jiayuan.chen@linux.dev> wrote:
>
> >
> > I think I don't need KEEP_TAG flag anymore, following patch works well and all kasan tests run successfully
> > with CONFIG_KASAN_SW_TAGS/CONFIG_KASAN_HW_TAGS/CONFIG_KASAN_GENERIC
> >
> Thanks for working on improving the vrealloc annotations!
>
> But I think we need to first fix the vrealloc issue you discovered in
> a separate patch (so that it can be backported), and then we can apply
> your other vrealloc changes on top later.
>
> So please implement a version of your fix with KEEP_TAG -- this would
> also allow Maciej to build on top.
Thanks, i will just use KEEP_TAG and make the patch as simple as possible.
CC Maciej
Thanks.
> >
> > diff --git a/mm/kasan/hw_tags.c b/mm/kasan/hw_tags.c
> > index 1c373cc4b3fa..8b819a9b2a27 100644
> > --- a/mm/kasan/hw_tags.c
> > +++ b/mm/kasan/hw_tags.c
> > @@ -394,6 +394,11 @@ void __kasan_poison_vmalloc(const void *start, unsigned long size)
> > * The physical pages backing the vmalloc() allocation are poisoned
> > * through the usual page_alloc paths.
> > */
> > + if (!is_vmalloc_or_module_addr(start))
> > + return;
> > +
> > + size = round_up(size, KASAN_GRANULE_SIZE);
> > + kasan_poison(start, size, KASAN_VMALLOC_INVALID, false);
> >
> This does not look good - we will end up poisoning the same memory
> twice, once here and once it's freed to page_alloc.
>
> Is this change required?
>
> >
> > }
> >
> > #endif
> > diff --git a/mm/kasan/kasan_test_c.c b/mm/kasan/kasan_test_c.c
> > index 2cafca31b092..a5f683c3abde 100644
> > --- a/mm/kasan/kasan_test_c.c
> > +++ b/mm/kasan/kasan_test_c.c
> > @@ -1840,6 +1840,84 @@ static void vmalloc_helpers_tags(struct kunit *test)
> > vfree(ptr);
> > }
> >
> > +
> > +static void vrealloc_helpers(struct kunit *test, bool tags)
> > +{
> > + char *ptr;
> > + size_t size = PAGE_SIZE / 2 - KASAN_GRANULE_SIZE - 5;
> > +
> > + if (!kasan_vmalloc_enabled())
> > + kunit_skip(test, "Test requires kasan.vmalloc=on");
> > +
> > + ptr = (char *)vmalloc(size);
> > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
> > +
> > + OPTIMIZER_HIDE_VAR(ptr);
> > +
> > + size += PAGE_SIZE / 2;
> > + ptr = vrealloc(ptr, size, GFP_KERNEL);
> > + /* Check that the returned pointer is tagged. */
> > + if (tags) {
> > + KUNIT_EXPECT_GE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_MIN);
> > + KUNIT_EXPECT_LT(test, (u8)get_tag(ptr), (u8)KASAN_TAG_KERNEL);
> > + }
> > + /* Make sure in-bounds accesses are valid. */
> > + ptr[0] = 0;
> > + ptr[size - 1] = 0;
> > +
> > + /* Make sure exported vmalloc helpers handle tagged pointers. */
> > + KUNIT_ASSERT_TRUE(test, is_vmalloc_addr(ptr));
> > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vmalloc_to_page(ptr));
> > +
> > + size -= PAGE_SIZE / 2;
> > + ptr = vrealloc(ptr, size, GFP_KERNEL);
> > +
> > + /* Check that the returned pointer is tagged. */
> > + KUNIT_EXPECT_GE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_MIN);
> > + KUNIT_EXPECT_LT(test, (u8)get_tag(ptr), (u8)KASAN_TAG_KERNEL);
> > +
> > + /* Make sure exported vmalloc helpers handle tagged pointers. */
> > + KUNIT_ASSERT_TRUE(test, is_vmalloc_addr(ptr));
> > + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vmalloc_to_page(ptr));
> > +
> > +
> > + /* This access must cause a KASAN report. */
> > + KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)ptr)[size + 5]);
> > +
> > +
> > +#if !IS_MODULE(CONFIG_KASAN_KUNIT_TEST)
> > + {
> > + int rv;
> > +
> > + /* Make sure vrealloc'ed memory permissions can be changed. */
> > + rv = set_memory_ro((unsigned long)ptr, 1);
> > + KUNIT_ASSERT_GE(test, rv, 0);
> > + rv = set_memory_rw((unsigned long)ptr, 1);
> > + KUNIT_ASSERT_GE(test, rv, 0);
> > + }
> > +#endif
> > +
> > + vfree(ptr);
> > +}
> > +
> > +static void vrealloc_helpers_tags(struct kunit *test)
> > +{
> > + /* This test is intended for tag-based modes. */
> > + KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC);
> > +
> > + KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_VMALLOC);
> > + vrealloc_helpers(test, true);
> > +}
> > +
> > +static void vrealloc_helpers_generic(struct kunit *test)
> > +{
> > + /* This test is intended for tag-based modes. */
> > + KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_GENERIC);
> > +
> > + KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_VMALLOC);
> > + vrealloc_helpers(test, false);
> > +}
> > +
> > static void vmalloc_oob(struct kunit *test)
> > {
> > char *v_ptr, *p_ptr;
> > @@ -2241,6 +2319,8 @@ static struct kunit_case kasan_kunit_test_cases[] = {
> > KUNIT_CASE_SLOW(kasan_atomics),
> > KUNIT_CASE(vmalloc_helpers_tags),
> > KUNIT_CASE(vmalloc_oob),
> > + KUNIT_CASE(vrealloc_helpers_tags),
> > + KUNIT_CASE(vrealloc_helpers_generic),
> > KUNIT_CASE(vmap_tags),
> > KUNIT_CASE(vm_map_ram_tags),
> > KUNIT_CASE(match_all_not_assigned),
> > diff --git a/mm/vmalloc.c b/mm/vmalloc.c
> > index 798b2ed21e46..9ba2e8a346d6 100644
> > --- a/mm/vmalloc.c
> > +++ b/mm/vmalloc.c
> > @@ -4128,6 +4128,7 @@ EXPORT_SYMBOL(vzalloc_node_noprof);
> > void *vrealloc_node_align_noprof(const void *p, size_t size, unsigned long align,
> > gfp_t flags, int nid)
> > {
> > + asan_vmalloc_flags_t flags;
> > struct vm_struct *vm = NULL;
> > size_t alloced_size = 0;
> > size_t old_size = 0;
> > @@ -4158,25 +4159,26 @@ void *vrealloc_node_align_noprof(const void *p, size_t size, unsigned long align
> > goto need_realloc;
> > }
> >
> > + flags = KASAN_VMALLOC_PROT_NORMAL | KASAN_VMALLOC_VM_ALLOC;
> > /*
> > * TODO: Shrink the vm_area, i.e. unmap and free unused pages. What
> > * would be a good heuristic for when to shrink the vm_area?
> > */
> > - if (size <= old_size) {
> > + if (p && size <= old_size) {
> > /* Zero out "freed" memory, potentially for future realloc. */
> > if (want_init_on_free() || want_init_on_alloc(flags))
> > memset((void *)p + size, 0, old_size - size);
> > vm->requested_size = size;
> > - kasan_poison_vmalloc(p + size, old_size - size);
> > + kasan_poison_vmalloc(p, alloced_size);
> > + p = kasan_unpoison_vmalloc(p, size, flags);
> > return (void *)p;
> > }
> >
> > /*
> > * We already have the bytes available in the allocation; use them.
> > */
> > - if (size <= alloced_size) {
> > - kasan_unpoison_vmalloc(p + old_size, size - old_size,
> > - KASAN_VMALLOC_PROT_NORMAL);
> > + if (p && size <= alloced_size) {
> > + p = kasan_unpoison_vmalloc(p, size, flags);
> > /*
> > * No need to zero memory here, as unused memory will have
> > * already been zeroed at initial allocation time or during
> >
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v1] mm/kasan: Fix incorrect unpoisoning in vrealloc for KASAN
2025-12-04 14:38 ` Jiayuan Chen
2025-12-04 15:06 ` Andrey Konovalov
@ 2025-12-04 15:19 ` Maciej Wieczor-Retman
1 sibling, 0 replies; 10+ messages in thread
From: Maciej Wieczor-Retman @ 2025-12-04 15:19 UTC (permalink / raw)
To: Jiayuan Chen
Cc: Maciej Wieczor-Retman, linux-mm, syzbot+997752115a851cb0cf36,
Andrey Ryabinin, Alexander Potapenko, Andrey Konovalov,
Dmitry Vyukov, Vincenzo Frascino, Andrew Morton,
Uladzislau Rezki, Danilo Krummrich, Kees Cook, kasan-dev,
linux-kernel
On 2025-12-04 at 14:38:12 +0000, Jiayuan Chen wrote:
>December 4, 2025 at 21:55, "Maciej Wieczor-Retman" <m.wieczorretman@pm.me mailto:m.wieczorretman@pm.me?to=%22Maciej%20Wieczor-Retman%22%20%3Cm.wieczorretman%40pm.me%3E > wrote:
>
>
>>
>> On 2025-12-03 at 02:05:11 +0000, Jiayuan Chen wrote:
>>
>> >
>> > December 3, 2025 at 04:48, "Maciej Wieczor-Retman" <maciej.wieczor-retman@intel.com mailto:maciej.wieczor-retman@intel.com?to=%22Maciej%20Wieczor-Retman%22%20%3Cmaciej.wieczor-retman%40intel.com%3E > wrote:
>> >
>> > >
>> > > Hi, I'm working on [1]. As Andrew pointed out to me the patches are quite
>> > > similar. I was wondering if you mind if the reuse_tag was an actual tag value?
>> > > Instead of just bool toggling the usage of kasan_random_tag()?
>> > >
>> > > I tested the problem I'm seeing, with your patch and the tags end up being reset.
>> > > That's because the vms[area] pointers that I want to unpoison don't have a tag
>> > > set, but generating a different random tag for each vms[] pointer crashes the
>> > > kernel down the line. So __kasan_unpoison_vmalloc() needs to be called on each
>> > > one but with the same tag.
>> > >
>> > > Arguably I noticed my series also just resets the tags right now, but I'm
>> > > working to correct it at the moment. I can send a fixed version tomorrow. Just
>> > > wanted to ask if having __kasan_unpoison_vmalloc() set an actual predefined tag
>> > > is a problem from your point of view?
>> > >
>> > > [1] https://lore.kernel.org/all/cover.1764685296.git.m.wieczorretman@pm.me/
>> > >
>> > Hi Maciej,
>> >
>> > It seems we're focusing on different issues, but feel free to reuse or modify the 'reuse_tag'.
>> > It's intended to preserve the tag in one 'vma'.
>> >
>> > I'd also be happy to help reproduce and test your changes to ensure the issue I encountered
>> > isn't regressed once you send a patch based on mine.
>> >
>> > Thanks.
>> >
>> After reading Andrey's comments on your patches and mine I tried applying all
>> the changes to test the flag approach. Now my patches don't modify any vrealloc
>> related code. I came up with something like this below from your patch. Just
>> tested it and it works fine on my end, does it look okay to you?
>>
...
Thanks for letting me know, glad it's working :)
In that case I'll go ahead and post my two patches with the vmalloc flag
addition. And thanks for pasting your code here, I suppose mine won't conflict
with yours but I'll check before sending.
kind regards
Maciej Wieczór-Retman
>I think I don't need KEEP_TAG flag anymore, following patch works well and all kasan tests run successfully
>with CONFIG_KASAN_SW_TAGS/CONFIG_KASAN_HW_TAGS/CONFIG_KASAN_GENERIC
>
>
>diff --git a/mm/kasan/hw_tags.c b/mm/kasan/hw_tags.c
>index 1c373cc4b3fa..8b819a9b2a27 100644
>--- a/mm/kasan/hw_tags.c
>+++ b/mm/kasan/hw_tags.c
>@@ -394,6 +394,11 @@ void __kasan_poison_vmalloc(const void *start, unsigned long size)
> * The physical pages backing the vmalloc() allocation are poisoned
> * through the usual page_alloc paths.
> */
>+ if (!is_vmalloc_or_module_addr(start))
>+ return;
>+
>+ size = round_up(size, KASAN_GRANULE_SIZE);
>+ kasan_poison(start, size, KASAN_VMALLOC_INVALID, false);
> }
>
> #endif
>diff --git a/mm/kasan/kasan_test_c.c b/mm/kasan/kasan_test_c.c
>index 2cafca31b092..a5f683c3abde 100644
>--- a/mm/kasan/kasan_test_c.c
>+++ b/mm/kasan/kasan_test_c.c
>@@ -1840,6 +1840,84 @@ static void vmalloc_helpers_tags(struct kunit *test)
> vfree(ptr);
> }
>
>+
>+static void vrealloc_helpers(struct kunit *test, bool tags)
>+{
>+ char *ptr;
>+ size_t size = PAGE_SIZE / 2 - KASAN_GRANULE_SIZE - 5;
>+
>+ if (!kasan_vmalloc_enabled())
>+ kunit_skip(test, "Test requires kasan.vmalloc=on");
>+
>+ ptr = (char *)vmalloc(size);
>+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
>+
>+ OPTIMIZER_HIDE_VAR(ptr);
>+
>+ size += PAGE_SIZE / 2;
>+ ptr = vrealloc(ptr, size, GFP_KERNEL);
>+ /* Check that the returned pointer is tagged. */
>+ if (tags) {
>+ KUNIT_EXPECT_GE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_MIN);
>+ KUNIT_EXPECT_LT(test, (u8)get_tag(ptr), (u8)KASAN_TAG_KERNEL);
>+ }
>+ /* Make sure in-bounds accesses are valid. */
>+ ptr[0] = 0;
>+ ptr[size - 1] = 0;
>+
>+ /* Make sure exported vmalloc helpers handle tagged pointers. */
>+ KUNIT_ASSERT_TRUE(test, is_vmalloc_addr(ptr));
>+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vmalloc_to_page(ptr));
>+
>+ size -= PAGE_SIZE / 2;
>+ ptr = vrealloc(ptr, size, GFP_KERNEL);
>+
>+ /* Check that the returned pointer is tagged. */
>+ KUNIT_EXPECT_GE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_MIN);
>+ KUNIT_EXPECT_LT(test, (u8)get_tag(ptr), (u8)KASAN_TAG_KERNEL);
>+
>+ /* Make sure exported vmalloc helpers handle tagged pointers. */
>+ KUNIT_ASSERT_TRUE(test, is_vmalloc_addr(ptr));
>+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vmalloc_to_page(ptr));
>+
>+
>+ /* This access must cause a KASAN report. */
>+ KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)ptr)[size + 5]);
>+
>+
>+#if !IS_MODULE(CONFIG_KASAN_KUNIT_TEST)
>+ {
>+ int rv;
>+
>+ /* Make sure vrealloc'ed memory permissions can be changed. */
>+ rv = set_memory_ro((unsigned long)ptr, 1);
>+ KUNIT_ASSERT_GE(test, rv, 0);
>+ rv = set_memory_rw((unsigned long)ptr, 1);
>+ KUNIT_ASSERT_GE(test, rv, 0);
>+ }
>+#endif
>+
>+ vfree(ptr);
>+}
>+
>+static void vrealloc_helpers_tags(struct kunit *test)
>+{
>+ /* This test is intended for tag-based modes. */
>+ KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC);
>+
>+ KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_VMALLOC);
>+ vrealloc_helpers(test, true);
>+}
>+
>+static void vrealloc_helpers_generic(struct kunit *test)
>+{
>+ /* This test is intended for tag-based modes. */
>+ KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_GENERIC);
>+
>+ KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_VMALLOC);
>+ vrealloc_helpers(test, false);
>+}
>+
> static void vmalloc_oob(struct kunit *test)
> {
> char *v_ptr, *p_ptr;
>@@ -2241,6 +2319,8 @@ static struct kunit_case kasan_kunit_test_cases[] = {
> KUNIT_CASE_SLOW(kasan_atomics),
> KUNIT_CASE(vmalloc_helpers_tags),
> KUNIT_CASE(vmalloc_oob),
>+ KUNIT_CASE(vrealloc_helpers_tags),
>+ KUNIT_CASE(vrealloc_helpers_generic),
> KUNIT_CASE(vmap_tags),
> KUNIT_CASE(vm_map_ram_tags),
> KUNIT_CASE(match_all_not_assigned),
>diff --git a/mm/vmalloc.c b/mm/vmalloc.c
>index 798b2ed21e46..9ba2e8a346d6 100644
>--- a/mm/vmalloc.c
>+++ b/mm/vmalloc.c
>@@ -4128,6 +4128,7 @@ EXPORT_SYMBOL(vzalloc_node_noprof);
> void *vrealloc_node_align_noprof(const void *p, size_t size, unsigned long align,
> gfp_t flags, int nid)
> {
>+ asan_vmalloc_flags_t flags;
> struct vm_struct *vm = NULL;
> size_t alloced_size = 0;
> size_t old_size = 0;
>@@ -4158,25 +4159,26 @@ void *vrealloc_node_align_noprof(const void *p, size_t size, unsigned long align
> goto need_realloc;
> }
>
>+ flags = KASAN_VMALLOC_PROT_NORMAL | KASAN_VMALLOC_VM_ALLOC;
> /*
> * TODO: Shrink the vm_area, i.e. unmap and free unused pages. What
> * would be a good heuristic for when to shrink the vm_area?
> */
>- if (size <= old_size) {
>+ if (p && size <= old_size) {
> /* Zero out "freed" memory, potentially for future realloc. */
> if (want_init_on_free() || want_init_on_alloc(flags))
> memset((void *)p + size, 0, old_size - size);
> vm->requested_size = size;
>- kasan_poison_vmalloc(p + size, old_size - size);
>+ kasan_poison_vmalloc(p, alloced_size);
>+ p = kasan_unpoison_vmalloc(p, size, flags);
> return (void *)p;
> }
>
> /*
> * We already have the bytes available in the allocation; use them.
> */
>- if (size <= alloced_size) {
>- kasan_unpoison_vmalloc(p + old_size, size - old_size,
>- KASAN_VMALLOC_PROT_NORMAL);
>+ if (p && size <= alloced_size) {
>+ p = kasan_unpoison_vmalloc(p, size, flags);
> /*
> * No need to zero memory here, as unused memory will have
> * already been zeroed at initial allocation time or during
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v1] mm/kasan: Fix incorrect unpoisoning in vrealloc for KASAN
2025-12-04 14:38 ` Jiayuan Chen
@ 2025-12-04 15:06 ` Andrey Konovalov
2025-12-04 15:35 ` Jiayuan Chen
2025-12-04 15:19 ` Maciej Wieczor-Retman
1 sibling, 1 reply; 10+ messages in thread
From: Andrey Konovalov @ 2025-12-04 15:06 UTC (permalink / raw)
To: Jiayuan Chen
Cc: Maciej Wieczor-Retman, Maciej Wieczor-Retman, linux-mm,
syzbot+997752115a851cb0cf36, Andrey Ryabinin,
Alexander Potapenko, Dmitry Vyukov, Vincenzo Frascino,
Andrew Morton, Uladzislau Rezki, Danilo Krummrich, Kees Cook,
kasan-dev, linux-kernel
On Thu, Dec 4, 2025 at 3:38 PM Jiayuan Chen <jiayuan.chen@linux.dev> wrote:
>
> I think I don't need KEEP_TAG flag anymore, following patch works well and all kasan tests run successfully
> with CONFIG_KASAN_SW_TAGS/CONFIG_KASAN_HW_TAGS/CONFIG_KASAN_GENERIC
Thanks for working on improving the vrealloc annotations!
But I think we need to first fix the vrealloc issue you discovered in
a separate patch (so that it can be backported), and then we can apply
your other vrealloc changes on top later.
So please implement a version of your fix with KEEP_TAG -- this would
also allow Maciej to build on top.
>
>
> diff --git a/mm/kasan/hw_tags.c b/mm/kasan/hw_tags.c
> index 1c373cc4b3fa..8b819a9b2a27 100644
> --- a/mm/kasan/hw_tags.c
> +++ b/mm/kasan/hw_tags.c
> @@ -394,6 +394,11 @@ void __kasan_poison_vmalloc(const void *start, unsigned long size)
> * The physical pages backing the vmalloc() allocation are poisoned
> * through the usual page_alloc paths.
> */
> + if (!is_vmalloc_or_module_addr(start))
> + return;
> +
> + size = round_up(size, KASAN_GRANULE_SIZE);
> + kasan_poison(start, size, KASAN_VMALLOC_INVALID, false);
This does not look good - we will end up poisoning the same memory
twice, once here and once it's freed to page_alloc.
Is this change required?
> }
>
> #endif
> diff --git a/mm/kasan/kasan_test_c.c b/mm/kasan/kasan_test_c.c
> index 2cafca31b092..a5f683c3abde 100644
> --- a/mm/kasan/kasan_test_c.c
> +++ b/mm/kasan/kasan_test_c.c
> @@ -1840,6 +1840,84 @@ static void vmalloc_helpers_tags(struct kunit *test)
> vfree(ptr);
> }
>
> +
> +static void vrealloc_helpers(struct kunit *test, bool tags)
> +{
> + char *ptr;
> + size_t size = PAGE_SIZE / 2 - KASAN_GRANULE_SIZE - 5;
> +
> + if (!kasan_vmalloc_enabled())
> + kunit_skip(test, "Test requires kasan.vmalloc=on");
> +
> + ptr = (char *)vmalloc(size);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
> +
> + OPTIMIZER_HIDE_VAR(ptr);
> +
> + size += PAGE_SIZE / 2;
> + ptr = vrealloc(ptr, size, GFP_KERNEL);
> + /* Check that the returned pointer is tagged. */
> + if (tags) {
> + KUNIT_EXPECT_GE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_MIN);
> + KUNIT_EXPECT_LT(test, (u8)get_tag(ptr), (u8)KASAN_TAG_KERNEL);
> + }
> + /* Make sure in-bounds accesses are valid. */
> + ptr[0] = 0;
> + ptr[size - 1] = 0;
> +
> + /* Make sure exported vmalloc helpers handle tagged pointers. */
> + KUNIT_ASSERT_TRUE(test, is_vmalloc_addr(ptr));
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vmalloc_to_page(ptr));
> +
> + size -= PAGE_SIZE / 2;
> + ptr = vrealloc(ptr, size, GFP_KERNEL);
> +
> + /* Check that the returned pointer is tagged. */
> + KUNIT_EXPECT_GE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_MIN);
> + KUNIT_EXPECT_LT(test, (u8)get_tag(ptr), (u8)KASAN_TAG_KERNEL);
> +
> + /* Make sure exported vmalloc helpers handle tagged pointers. */
> + KUNIT_ASSERT_TRUE(test, is_vmalloc_addr(ptr));
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vmalloc_to_page(ptr));
> +
> +
> + /* This access must cause a KASAN report. */
> + KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)ptr)[size + 5]);
> +
> +
> +#if !IS_MODULE(CONFIG_KASAN_KUNIT_TEST)
> + {
> + int rv;
> +
> + /* Make sure vrealloc'ed memory permissions can be changed. */
> + rv = set_memory_ro((unsigned long)ptr, 1);
> + KUNIT_ASSERT_GE(test, rv, 0);
> + rv = set_memory_rw((unsigned long)ptr, 1);
> + KUNIT_ASSERT_GE(test, rv, 0);
> + }
> +#endif
> +
> + vfree(ptr);
> +}
> +
> +static void vrealloc_helpers_tags(struct kunit *test)
> +{
> + /* This test is intended for tag-based modes. */
> + KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC);
> +
> + KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_VMALLOC);
> + vrealloc_helpers(test, true);
> +}
> +
> +static void vrealloc_helpers_generic(struct kunit *test)
> +{
> + /* This test is intended for tag-based modes. */
> + KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_GENERIC);
> +
> + KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_VMALLOC);
> + vrealloc_helpers(test, false);
> +}
> +
> static void vmalloc_oob(struct kunit *test)
> {
> char *v_ptr, *p_ptr;
> @@ -2241,6 +2319,8 @@ static struct kunit_case kasan_kunit_test_cases[] = {
> KUNIT_CASE_SLOW(kasan_atomics),
> KUNIT_CASE(vmalloc_helpers_tags),
> KUNIT_CASE(vmalloc_oob),
> + KUNIT_CASE(vrealloc_helpers_tags),
> + KUNIT_CASE(vrealloc_helpers_generic),
> KUNIT_CASE(vmap_tags),
> KUNIT_CASE(vm_map_ram_tags),
> KUNIT_CASE(match_all_not_assigned),
> diff --git a/mm/vmalloc.c b/mm/vmalloc.c
> index 798b2ed21e46..9ba2e8a346d6 100644
> --- a/mm/vmalloc.c
> +++ b/mm/vmalloc.c
> @@ -4128,6 +4128,7 @@ EXPORT_SYMBOL(vzalloc_node_noprof);
> void *vrealloc_node_align_noprof(const void *p, size_t size, unsigned long align,
> gfp_t flags, int nid)
> {
> + asan_vmalloc_flags_t flags;
> struct vm_struct *vm = NULL;
> size_t alloced_size = 0;
> size_t old_size = 0;
> @@ -4158,25 +4159,26 @@ void *vrealloc_node_align_noprof(const void *p, size_t size, unsigned long align
> goto need_realloc;
> }
>
> + flags = KASAN_VMALLOC_PROT_NORMAL | KASAN_VMALLOC_VM_ALLOC;
> /*
> * TODO: Shrink the vm_area, i.e. unmap and free unused pages. What
> * would be a good heuristic for when to shrink the vm_area?
> */
> - if (size <= old_size) {
> + if (p && size <= old_size) {
> /* Zero out "freed" memory, potentially for future realloc. */
> if (want_init_on_free() || want_init_on_alloc(flags))
> memset((void *)p + size, 0, old_size - size);
> vm->requested_size = size;
> - kasan_poison_vmalloc(p + size, old_size - size);
> + kasan_poison_vmalloc(p, alloced_size);
> + p = kasan_unpoison_vmalloc(p, size, flags);
> return (void *)p;
> }
>
> /*
> * We already have the bytes available in the allocation; use them.
> */
> - if (size <= alloced_size) {
> - kasan_unpoison_vmalloc(p + old_size, size - old_size,
> - KASAN_VMALLOC_PROT_NORMAL);
> + if (p && size <= alloced_size) {
> + p = kasan_unpoison_vmalloc(p, size, flags);
> /*
> * No need to zero memory here, as unused memory will have
> * already been zeroed at initial allocation time or during
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v1] mm/kasan: Fix incorrect unpoisoning in vrealloc for KASAN
2025-12-04 13:55 Maciej Wieczor-Retman
@ 2025-12-04 14:38 ` Jiayuan Chen
2025-12-04 15:06 ` Andrey Konovalov
2025-12-04 15:19 ` Maciej Wieczor-Retman
0 siblings, 2 replies; 10+ messages in thread
From: Jiayuan Chen @ 2025-12-04 14:38 UTC (permalink / raw)
To: Maciej Wieczor-Retman
Cc: Maciej Wieczor-Retman, linux-mm, syzbot+997752115a851cb0cf36,
Andrey Ryabinin, Alexander Potapenko, Andrey Konovalov,
Dmitry Vyukov, Vincenzo Frascino, Andrew Morton,
Uladzislau Rezki, Danilo Krummrich, Kees Cook, kasan-dev,
linux-kernel
December 4, 2025 at 21:55, "Maciej Wieczor-Retman" <m.wieczorretman@pm.me mailto:m.wieczorretman@pm.me?to=%22Maciej%20Wieczor-Retman%22%20%3Cm.wieczorretman%40pm.me%3E > wrote:
>
> On 2025-12-03 at 02:05:11 +0000, Jiayuan Chen wrote:
>
> >
> > December 3, 2025 at 04:48, "Maciej Wieczor-Retman" <maciej.wieczor-retman@intel.com mailto:maciej.wieczor-retman@intel.com?to=%22Maciej%20Wieczor-Retman%22%20%3Cmaciej.wieczor-retman%40intel.com%3E > wrote:
> >
> > >
> > > Hi, I'm working on [1]. As Andrew pointed out to me the patches are quite
> > > similar. I was wondering if you mind if the reuse_tag was an actual tag value?
> > > Instead of just bool toggling the usage of kasan_random_tag()?
> > >
> > > I tested the problem I'm seeing, with your patch and the tags end up being reset.
> > > That's because the vms[area] pointers that I want to unpoison don't have a tag
> > > set, but generating a different random tag for each vms[] pointer crashes the
> > > kernel down the line. So __kasan_unpoison_vmalloc() needs to be called on each
> > > one but with the same tag.
> > >
> > > Arguably I noticed my series also just resets the tags right now, but I'm
> > > working to correct it at the moment. I can send a fixed version tomorrow. Just
> > > wanted to ask if having __kasan_unpoison_vmalloc() set an actual predefined tag
> > > is a problem from your point of view?
> > >
> > > [1] https://lore.kernel.org/all/cover.1764685296.git.m.wieczorretman@pm.me/
> > >
> > Hi Maciej,
> >
> > It seems we're focusing on different issues, but feel free to reuse or modify the 'reuse_tag'.
> > It's intended to preserve the tag in one 'vma'.
> >
> > I'd also be happy to help reproduce and test your changes to ensure the issue I encountered
> > isn't regressed once you send a patch based on mine.
> >
> > Thanks.
> >
> After reading Andrey's comments on your patches and mine I tried applying all
> the changes to test the flag approach. Now my patches don't modify any vrealloc
> related code. I came up with something like this below from your patch. Just
> tested it and it works fine on my end, does it look okay to you?
>
> ---
> include/linux/kasan.h | 1 +
> mm/kasan/hw_tags.c | 3 ++-
> mm/kasan/shadow.c | 4 +++-
> mm/vmalloc.c | 6 ++++--
> 4 files changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/include/linux/kasan.h b/include/linux/kasan.h
> index 03e263fb9fa1..068f62d07122 100644
> --- a/include/linux/kasan.h
> +++ b/include/linux/kasan.h
> @@ -28,6 +28,7 @@ typedef unsigned int __bitwise kasan_vmalloc_flags_t;
> #define KASAN_VMALLOC_INIT ((__force kasan_vmalloc_flags_t)0x01u)
> #define KASAN_VMALLOC_VM_ALLOC ((__force kasan_vmalloc_flags_t)0x02u)
> #define KASAN_VMALLOC_PROT_NORMAL ((__force kasan_vmalloc_flags_t)0x04u)
> +#define KASAN_VMALLOC_KEEP_TAG ((__force kasan_vmalloc_flags_t)0x08u)
>
> #define KASAN_VMALLOC_PAGE_RANGE 0x1 /* Apply exsiting page range */
> #define KASAN_VMALLOC_TLB_FLUSH 0x2 /* TLB flush */
> diff --git a/mm/kasan/hw_tags.c b/mm/kasan/hw_tags.c
> index 1c373cc4b3fa..e6d7ee544c28 100644
> --- a/mm/kasan/hw_tags.c
> +++ b/mm/kasan/hw_tags.c
> @@ -361,7 +361,8 @@ void *__kasan_unpoison_vmalloc(const void *start, unsigned long size,
> return (void *)start;
> }
>
> - tag = kasan_random_tag();
> + tag = (flags & KASAN_VMALLOC_KEEP_TAG) ? get_tag(start) :
> + kasan_random_tag();
> start = set_tag(start, tag);
>
> /* Unpoison and initialize memory up to size. */
> diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c
> index 5d2a876035d6..6dd61093d1d5 100644
> --- a/mm/kasan/shadow.c
> +++ b/mm/kasan/shadow.c
> @@ -648,7 +648,9 @@ void *__kasan_unpoison_vmalloc(const void *start, unsigned long size,
> !(flags & KASAN_VMALLOC_PROT_NORMAL))
> return (void *)start;
>
> - start = set_tag(start, kasan_random_tag());
> + if (!(flags & KASAN_VMALLOC_KEEP_TAG))
> + start = 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 ead22a610b18..c939dc04baa5 100644
> --- a/mm/vmalloc.c
> +++ b/mm/vmalloc.c
> @@ -4180,8 +4180,10 @@ 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 <= alloced_size) {
> - kasan_unpoison_vmalloc(p + old_size, size - old_size,
> - KASAN_VMALLOC_PROT_NORMAL);
> + kasan_unpoison_vmalloc(p, size,
> + KASAN_VMALLOC_PROT_NORMAL |
> + KASAN_VMALLOC_VM_ALLOC |
> + KASAN_VMALLOC_KEEP_TAG);
> /*
> * No need to zero memory here, as unused memory will have
> * already been zeroed at initial allocation time or during
>
> --
> Kind regards
> Maciej Wieczór-Retman
>
I think I don't need KEEP_TAG flag anymore, following patch works well and all kasan tests run successfully
with CONFIG_KASAN_SW_TAGS/CONFIG_KASAN_HW_TAGS/CONFIG_KASAN_GENERIC
diff --git a/mm/kasan/hw_tags.c b/mm/kasan/hw_tags.c
index 1c373cc4b3fa..8b819a9b2a27 100644
--- a/mm/kasan/hw_tags.c
+++ b/mm/kasan/hw_tags.c
@@ -394,6 +394,11 @@ void __kasan_poison_vmalloc(const void *start, unsigned long size)
* The physical pages backing the vmalloc() allocation are poisoned
* through the usual page_alloc paths.
*/
+ if (!is_vmalloc_or_module_addr(start))
+ return;
+
+ size = round_up(size, KASAN_GRANULE_SIZE);
+ kasan_poison(start, size, KASAN_VMALLOC_INVALID, false);
}
#endif
diff --git a/mm/kasan/kasan_test_c.c b/mm/kasan/kasan_test_c.c
index 2cafca31b092..a5f683c3abde 100644
--- a/mm/kasan/kasan_test_c.c
+++ b/mm/kasan/kasan_test_c.c
@@ -1840,6 +1840,84 @@ static void vmalloc_helpers_tags(struct kunit *test)
vfree(ptr);
}
+
+static void vrealloc_helpers(struct kunit *test, bool tags)
+{
+ char *ptr;
+ size_t size = PAGE_SIZE / 2 - KASAN_GRANULE_SIZE - 5;
+
+ if (!kasan_vmalloc_enabled())
+ kunit_skip(test, "Test requires kasan.vmalloc=on");
+
+ ptr = (char *)vmalloc(size);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
+
+ OPTIMIZER_HIDE_VAR(ptr);
+
+ size += PAGE_SIZE / 2;
+ ptr = vrealloc(ptr, size, GFP_KERNEL);
+ /* Check that the returned pointer is tagged. */
+ if (tags) {
+ KUNIT_EXPECT_GE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_MIN);
+ KUNIT_EXPECT_LT(test, (u8)get_tag(ptr), (u8)KASAN_TAG_KERNEL);
+ }
+ /* Make sure in-bounds accesses are valid. */
+ ptr[0] = 0;
+ ptr[size - 1] = 0;
+
+ /* Make sure exported vmalloc helpers handle tagged pointers. */
+ KUNIT_ASSERT_TRUE(test, is_vmalloc_addr(ptr));
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vmalloc_to_page(ptr));
+
+ size -= PAGE_SIZE / 2;
+ ptr = vrealloc(ptr, size, GFP_KERNEL);
+
+ /* Check that the returned pointer is tagged. */
+ KUNIT_EXPECT_GE(test, (u8)get_tag(ptr), (u8)KASAN_TAG_MIN);
+ KUNIT_EXPECT_LT(test, (u8)get_tag(ptr), (u8)KASAN_TAG_KERNEL);
+
+ /* Make sure exported vmalloc helpers handle tagged pointers. */
+ KUNIT_ASSERT_TRUE(test, is_vmalloc_addr(ptr));
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vmalloc_to_page(ptr));
+
+
+ /* This access must cause a KASAN report. */
+ KUNIT_EXPECT_KASAN_FAIL_READ(test, ((volatile char *)ptr)[size + 5]);
+
+
+#if !IS_MODULE(CONFIG_KASAN_KUNIT_TEST)
+ {
+ int rv;
+
+ /* Make sure vrealloc'ed memory permissions can be changed. */
+ rv = set_memory_ro((unsigned long)ptr, 1);
+ KUNIT_ASSERT_GE(test, rv, 0);
+ rv = set_memory_rw((unsigned long)ptr, 1);
+ KUNIT_ASSERT_GE(test, rv, 0);
+ }
+#endif
+
+ vfree(ptr);
+}
+
+static void vrealloc_helpers_tags(struct kunit *test)
+{
+ /* This test is intended for tag-based modes. */
+ KASAN_TEST_NEEDS_CONFIG_OFF(test, CONFIG_KASAN_GENERIC);
+
+ KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_VMALLOC);
+ vrealloc_helpers(test, true);
+}
+
+static void vrealloc_helpers_generic(struct kunit *test)
+{
+ /* This test is intended for tag-based modes. */
+ KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_GENERIC);
+
+ KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_VMALLOC);
+ vrealloc_helpers(test, false);
+}
+
static void vmalloc_oob(struct kunit *test)
{
char *v_ptr, *p_ptr;
@@ -2241,6 +2319,8 @@ static struct kunit_case kasan_kunit_test_cases[] = {
KUNIT_CASE_SLOW(kasan_atomics),
KUNIT_CASE(vmalloc_helpers_tags),
KUNIT_CASE(vmalloc_oob),
+ KUNIT_CASE(vrealloc_helpers_tags),
+ KUNIT_CASE(vrealloc_helpers_generic),
KUNIT_CASE(vmap_tags),
KUNIT_CASE(vm_map_ram_tags),
KUNIT_CASE(match_all_not_assigned),
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 798b2ed21e46..9ba2e8a346d6 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -4128,6 +4128,7 @@ EXPORT_SYMBOL(vzalloc_node_noprof);
void *vrealloc_node_align_noprof(const void *p, size_t size, unsigned long align,
gfp_t flags, int nid)
{
+ asan_vmalloc_flags_t flags;
struct vm_struct *vm = NULL;
size_t alloced_size = 0;
size_t old_size = 0;
@@ -4158,25 +4159,26 @@ void *vrealloc_node_align_noprof(const void *p, size_t size, unsigned long align
goto need_realloc;
}
+ flags = KASAN_VMALLOC_PROT_NORMAL | KASAN_VMALLOC_VM_ALLOC;
/*
* TODO: Shrink the vm_area, i.e. unmap and free unused pages. What
* would be a good heuristic for when to shrink the vm_area?
*/
- if (size <= old_size) {
+ if (p && size <= old_size) {
/* Zero out "freed" memory, potentially for future realloc. */
if (want_init_on_free() || want_init_on_alloc(flags))
memset((void *)p + size, 0, old_size - size);
vm->requested_size = size;
- kasan_poison_vmalloc(p + size, old_size - size);
+ kasan_poison_vmalloc(p, alloced_size);
+ p = kasan_unpoison_vmalloc(p, size, flags);
return (void *)p;
}
/*
* We already have the bytes available in the allocation; use them.
*/
- if (size <= alloced_size) {
- kasan_unpoison_vmalloc(p + old_size, size - old_size,
- KASAN_VMALLOC_PROT_NORMAL);
+ if (p && size <= alloced_size) {
+ p = kasan_unpoison_vmalloc(p, size, flags);
/*
* No need to zero memory here, as unused memory will have
* already been zeroed at initial allocation time or during
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v1] mm/kasan: Fix incorrect unpoisoning in vrealloc for KASAN
@ 2025-12-04 13:55 Maciej Wieczor-Retman
2025-12-04 14:38 ` Jiayuan Chen
0 siblings, 1 reply; 10+ messages in thread
From: Maciej Wieczor-Retman @ 2025-12-04 13:55 UTC (permalink / raw)
To: Jiayuan Chen
Cc: Maciej Wieczor-Retman, linux-mm, syzbot+997752115a851cb0cf36,
Andrey Ryabinin, Alexander Potapenko, Andrey Konovalov,
Dmitry Vyukov, Vincenzo Frascino, Andrew Morton,
Uladzislau Rezki, Danilo Krummrich, Kees Cook, kasan-dev,
linux-kernel
On 2025-12-03 at 02:05:11 +0000, Jiayuan Chen wrote:
>December 3, 2025 at 04:48, "Maciej Wieczor-Retman" <maciej.wieczor-retman@intel.com mailto:maciej.wieczor-retman@intel.com?to=%22Maciej%20Wieczor-Retman%22%20%3Cmaciej.wieczor-retman%40intel.com%3E > wrote:
>>
>> Hi, I'm working on [1]. As Andrew pointed out to me the patches are quite
>> similar. I was wondering if you mind if the reuse_tag was an actual tag value?
>> Instead of just bool toggling the usage of kasan_random_tag()?
>>
>> I tested the problem I'm seeing, with your patch and the tags end up being reset.
>> That's because the vms[area] pointers that I want to unpoison don't have a tag
>> set, but generating a different random tag for each vms[] pointer crashes the
>> kernel down the line. So __kasan_unpoison_vmalloc() needs to be called on each
>> one but with the same tag.
>>
>> Arguably I noticed my series also just resets the tags right now, but I'm
>> working to correct it at the moment. I can send a fixed version tomorrow. Just
>> wanted to ask if having __kasan_unpoison_vmalloc() set an actual predefined tag
>> is a problem from your point of view?
>>
>> [1] https://lore.kernel.org/all/cover.1764685296.git.m.wieczorretman@pm.me/
>>
>
>Hi Maciej,
>
>It seems we're focusing on different issues, but feel free to reuse or modify the 'reuse_tag'.
>It's intended to preserve the tag in one 'vma'.
>
>I'd also be happy to help reproduce and test your changes to ensure the issue I encountered
>isn't regressed once you send a patch based on mine.
>
>Thanks.
After reading Andrey's comments on your patches and mine I tried applying all
the changes to test the flag approach. Now my patches don't modify any vrealloc
related code. I came up with something like this below from your patch. Just
tested it and it works fine on my end, does it look okay to you?
---
include/linux/kasan.h | 1 +
mm/kasan/hw_tags.c | 3 ++-
mm/kasan/shadow.c | 4 +++-
mm/vmalloc.c | 6 ++++--
4 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/include/linux/kasan.h b/include/linux/kasan.h
index 03e263fb9fa1..068f62d07122 100644
--- a/include/linux/kasan.h
+++ b/include/linux/kasan.h
@@ -28,6 +28,7 @@ typedef unsigned int __bitwise kasan_vmalloc_flags_t;
#define KASAN_VMALLOC_INIT ((__force kasan_vmalloc_flags_t)0x01u)
#define KASAN_VMALLOC_VM_ALLOC ((__force kasan_vmalloc_flags_t)0x02u)
#define KASAN_VMALLOC_PROT_NORMAL ((__force kasan_vmalloc_flags_t)0x04u)
+#define KASAN_VMALLOC_KEEP_TAG ((__force kasan_vmalloc_flags_t)0x08u)
#define KASAN_VMALLOC_PAGE_RANGE 0x1 /* Apply exsiting page range */
#define KASAN_VMALLOC_TLB_FLUSH 0x2 /* TLB flush */
diff --git a/mm/kasan/hw_tags.c b/mm/kasan/hw_tags.c
index 1c373cc4b3fa..e6d7ee544c28 100644
--- a/mm/kasan/hw_tags.c
+++ b/mm/kasan/hw_tags.c
@@ -361,7 +361,8 @@ void *__kasan_unpoison_vmalloc(const void *start, unsigned long size,
return (void *)start;
}
- tag = kasan_random_tag();
+ tag = (flags & KASAN_VMALLOC_KEEP_TAG) ? get_tag(start) :
+ kasan_random_tag();
start = set_tag(start, tag);
/* Unpoison and initialize memory up to size. */
diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c
index 5d2a876035d6..6dd61093d1d5 100644
--- a/mm/kasan/shadow.c
+++ b/mm/kasan/shadow.c
@@ -648,7 +648,9 @@ void *__kasan_unpoison_vmalloc(const void *start, unsigned long size,
!(flags & KASAN_VMALLOC_PROT_NORMAL))
return (void *)start;
- start = set_tag(start, kasan_random_tag());
+ if (!(flags & KASAN_VMALLOC_KEEP_TAG))
+ start = 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 ead22a610b18..c939dc04baa5 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -4180,8 +4180,10 @@ 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 <= alloced_size) {
- kasan_unpoison_vmalloc(p + old_size, size - old_size,
- KASAN_VMALLOC_PROT_NORMAL);
+ kasan_unpoison_vmalloc(p, size,
+ KASAN_VMALLOC_PROT_NORMAL |
+ KASAN_VMALLOC_VM_ALLOC |
+ KASAN_VMALLOC_KEEP_TAG);
/*
* No need to zero memory here, as unused memory will have
* already been zeroed at initial allocation time or during
--
Kind regards
Maciej Wieczór-Retman
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v1] mm/kasan: Fix incorrect unpoisoning in vrealloc for KASAN
@ 2025-12-03 7:30 Maciej Wieczór-Retman
0 siblings, 0 replies; 10+ messages in thread
From: Maciej Wieczór-Retman @ 2025-12-03 7:30 UTC (permalink / raw)
To: Jiayuan Chen
Cc: Maciej Wieczor-Retman, linux-mm, syzbot+997752115a851cb0cf36,
Andrey Ryabinin, Alexander Potapenko, Andrey Konovalov,
Dmitry Vyukov, Vincenzo Frascino, Andrew Morton,
Uladzislau Rezki, Danilo Krummrich, Kees Cook, kasan-dev,
linux-kernel
On 2025-12-03 at 02:05:11 +0000, Jiayuan Chen wrote:
>December 3, 2025 at 04:48, "Maciej Wieczor-Retman"
><maciej.wieczor-retman@intel.com
>mailto:maciej.wieczor-retman@intel.com?to=%22Maciej%20Wieczor-Retman%22%20%3Cmaciej.wieczor-retman%40intel.com%3E
>> wrote:
>>
>> Hi, I'm working on [1]. As Andrew pointed out to me the patches are quite
>> similar. I was wondering if you mind if the reuse_tag was an actual tag value?
>> Instead of just bool toggling the usage of kasan_random_tag()?
>>
>> I tested the problem I'm seeing, with your patch and the tags end up being reset.
>> That's because the vms[area] pointers that I want to unpoison don't have a tag
>> set, but generating a different random tag for each vms[] pointer crashes the
>> kernel down the line. So __kasan_unpoison_vmalloc() needs to be called on each
>> one but with the same tag.
>>
>> Arguably I noticed my series also just resets the tags right now, but I'm
>> working to correct it at the moment. I can send a fixed version tomorrow. Just
>> wanted to ask if having __kasan_unpoison_vmalloc() set an actual predefined tag
>> is a problem from your point of view?
>>
>> [1] https://lore.kernel.org/all/cover.1764685296.git.m.wieczorretman@pm.me/
>>
>
>
>Hi Maciej,
>
>It seems we're focusing on different issues, but feel free to reuse or modify the 'reuse_tag'.
>It's intended to preserve the tag in one 'vma'.
>
>I'd also be happy to help reproduce and test your changes to ensure the issue I encountered
>isn't regressed once you send a patch based on mine.
>
>Thanks.
Yes, the final issues are different, just we both want to use
__kasan_unpoison_vmalloc slightly differently.
Okay, then I'll rebase my patches onto your patch, restest on my end and
resubmit my series. I'll add you to CC and reply in this thread too.
Thanks :)
kind regards
Maciej Wieczór-Retman
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-12-04 15:35 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <20251128111516.244497-1-jiayuan.chen@linux.dev>
2025-12-02 20:48 ` [PATCH v1] mm/kasan: Fix incorrect unpoisoning in vrealloc for KASAN Maciej Wieczor-Retman
2025-12-03 2:05 ` Jiayuan Chen
2025-12-02 23:23 ` Kees Cook
2025-12-03 1:29 ` Jiayuan Chen
2025-12-03 7:30 Maciej Wieczór-Retman
2025-12-04 13:55 Maciej Wieczor-Retman
2025-12-04 14:38 ` Jiayuan Chen
2025-12-04 15:06 ` Andrey Konovalov
2025-12-04 15:35 ` Jiayuan Chen
2025-12-04 15:19 ` Maciej Wieczor-Retman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox