From: "Lorenzo Stoakes (Oracle)" <ljs@kernel.org>
To: Jiakai Xu <jiakaipeanut@gmail.com>
Cc: LKML <linux-kernel@vger.kernel.org>,
linux-mm@kvack.org, Liam.Howlett@oracle.com,
akpm@linux-foundation.org, david@kernel.org,
harry.yoo@oracle.com, jannh@google.com, riel@surriel.com,
vbabka@kernel.org, Sasha Levin <sashal@kernel.org>
Subject: Re: [BUG] WARNING in unlink_anon_vmas()
Date: Wed, 18 Mar 2026 11:55:42 +0000 [thread overview]
Message-ID: <b4e59cb0-c57c-472e-a70c-10ac450f4a6f@lucifer.local> (raw)
In-Reply-To: <12501051-98d4-479a-8f10-547b2c08ad59@lucifer.local>
+cc Sasha
On Wed, Mar 18, 2026 at 10:59:33AM +0000, Lorenzo Stoakes (Oracle) wrote:
> (-cc old email)
>
> On Wed, Mar 18, 2026 at 06:42:49PM +0800, Jiakai Xu wrote:
> > Hi all,
> >
> > While fuzzing the KVM subsystem on RISC-V, I stumbled upon a kernel WARNING
> > that triggers in unlink_anon_vmas().
>
> Thanks!
>
> Will have a look at this.
>
> >
> > WARNING: mm/rmap.c:528 at unlink_anon_vmas+0x562/0x768 mm/rmap.c:528
> > unlink_anon_vmas+0x562/0x768 mm/rmap.c:528
>
> Assuming there's not some big mismatch with kernel versions this is:
>
> VM_WARN_ON(anon_vma->num_active_vmas);
OK so this _was_ reported by Sasha (via an AI assessment), but it completely
dropped off my radar sorry about that!
https://lore.kernel.org/linux-mm/20260302151547.2389070-1-sashal@kernel.org/
I want to fix this a slightly different way though.
SO what's happening is in dup_anon_vma() we do:
static int dup_anon_vma(struct vm_area_struct *dst,
struct vm_area_struct *src, struct vm_area_struct **dup)
{
...
dst->anon_vma = src->anon_vma;
ret = anon_vma_clone(dst, src, VMA_OP_MERGE_UNFAULTED);
if (ret)
return ret; <-- fault injection error here
*dup = dst; <-- NOT set
...
}
Then:
int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src,
enum vma_operation operation)
{
...
list_for_each_entry(pavc, &src->anon_vma_chain, same_vma) {
avc = anon_vma_chain_alloc(GFP_KERNEL); <-- FAULT INJECTED HERE
if (!avc)
goto enomem_failure; <-- so we do this
anon_vma_chain_assign(dst, avc, pavc->anon_vma);
}
...
if (operation != VMA_OP_FORK)
dst->anon_vma->num_active_vmas++; <-- does NOT get run
...
enomem_failure:
cleanup_partial_anon_vmas(dst);
return -ENOMEM;
}
We only clear down the partially allocated anon_vma_chain objects:
static void cleanup_partial_anon_vmas(struct vm_area_struct *vma)
{
struct anon_vma_chain *avc, *next;
list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) {
list_del(&avc->same_vma);
anon_vma_chain_free(avc);
}
}
But, crucially, dst->anon_vma is LEFT IN PLACE.
So on process exit, we call into unlink_anon_vmas() for that VMA:
void unlink_anon_vmas(struct vm_area_struct *vma)
{
...
struct anon_vma *active_anon_vma = vma->anon_vma; <-- is SET
...
/* Unfaulted is a no-op. */
if (!active_anon_vma) { <-- is not called
VM_WARN_ON_ONCE(!list_empty(&vma->anon_vma_chain));
return;
}
...
active_anon_vma->num_active_vmas--; <-- Incorrect (*)
...
list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) {
...
VM_WARN_ON(anon_vma->num_active_vmas); <-- triggers
put_anon_vma(anon_vma);
...
}
}
* If anon_vma->num_active_vmas was 0, it underflows, but otherwise it'll get
decrement one time too many, and so will _eventually underflow_ guaranteed and
trigger the bug for for VMAs associated with this anon_vma.
The fix is to set vma->anon_vma = NULL in this situation, which I think is best
done in the cleanup code as I said at
https://lore.kernel.org/linux-mm/a709c736-fd76-4bc9-a1d2-e1351742b321@lucifer.local/
but then... didn't do as it dropped off my radar (oops!)
Will send a fix + cc, attribute Reported-by etc., thanks very much for reporting
this Jiakai, was very useful!
Cheers, Lorenzo
next prev parent reply other threads:[~2026-03-18 11:55 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-18 10:42 Jiakai Xu
2026-03-18 10:57 ` David Hildenbrand (Arm)
2026-03-18 11:05 ` Lorenzo Stoakes (Oracle)
2026-03-18 10:59 ` Lorenzo Stoakes (Oracle)
2026-03-18 11:23 ` Lorenzo Stoakes (Oracle)
2026-03-18 11:41 ` Lorenzo Stoakes (Oracle)
2026-03-18 11:55 ` Lorenzo Stoakes (Oracle) [this message]
2026-03-18 12:28 ` Lorenzo Stoakes (Oracle)
2026-03-19 1:16 ` Jiakai Xu
2026-03-19 10:53 ` Lorenzo Stoakes (Oracle)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=b4e59cb0-c57c-472e-a70c-10ac450f4a6f@lucifer.local \
--to=ljs@kernel.org \
--cc=Liam.Howlett@oracle.com \
--cc=akpm@linux-foundation.org \
--cc=david@kernel.org \
--cc=harry.yoo@oracle.com \
--cc=jannh@google.com \
--cc=jiakaipeanut@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=riel@surriel.com \
--cc=sashal@kernel.org \
--cc=vbabka@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox