linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
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


  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