All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: Yan Zhao <yan.y.zhao@intel.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>,
	David Hildenbrand <david@kernel.org>,
	kvm@vger.kernel.org,  linux-kernel@vger.kernel.org,
	Vishal Annapurve <vannapurve@google.com>
Subject: Re: [PATCH v2] KVM: guest_memfd: Elaborate on how release() vs. get_pfn() is safe against UAF
Date: Mon, 21 Sep 2026 06:40:15 -0700	[thread overview]
Message-ID: <arEzv8b2IMHYcHsZ@google.com> (raw)
In-Reply-To: <aq/XwK71uNfLvUux@yzhao56-desk.sh.intel.com>

On Sun, Sep 20, 2026, Yan Zhao wrote:
> On Wed, Aug 26, 2026 at 09:56:47AM -0700, Sean Christopherson wrote:
> > Add more context and information to the comment in kvm_gmem_release() that
> > explains why there's no synchronization on RCU _or_ kvm->srcu.  Point (b)
> > from commit 67b43038ce14 ("KVM: guest_memfd: Remove RCU-protected attribute
> > from slot->gmem.file")
> > 
> >       b) kvm->srcu ensures that kvm_gmem_unbind() and freeing of a memslot
> >          occur after the memslot is no longer visible to kvm_gmem_get_pfn().
> > 
> > is especially difficult to fully grok, particularly in light of commit
> > ae431059e75d ("KVM: guest_memfd: Remove bindings on memslot deletion when
> > gmem is dying"), which addressed a race between unbind() and release().
> > 
> > See the extended on-list discussion[*] for more details about exactly what
> > KVM guards against, and how.
> > 
> > No functional change intended.
> > 
> > Link: https://lore.kernel.org/all/CAEvNRgGmyd1yqQXsnz5hWRZpBZUs%3DpiEWbEaqP9%2Bcz9ZqEMQ6g@mail.gmail.com [*]
> > Cc: Yan Zhao <yan.y.zhao@intel.com>
> > Cc: Vishal Annapurve <vannapurve@google.com>
> > Signed-off-by: Sean Christopherson <seanjc@google.com>
> > ---
> > 
> > v2: Explain how this all works in even gorier detail. [Yan]
> > 
> > v1: https://lore.kernel.org/all/20251113232229.1698886-1-seanjc@google.com
> > 
> >  virt/kvm/guest_memfd.c | 50 +++++++++++++++++++++++++++++++++++++-----
> >  1 file changed, 44 insertions(+), 6 deletions(-)
> > 
> > diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
> > index b596486d184c..7f1c6a0f8039 100644
> > --- a/virt/kvm/guest_memfd.c
> > +++ b/virt/kvm/guest_memfd.c
> > @@ -300,17 +300,55 @@ static int kvm_gmem_release(struct inode *inode, struct file *file)
> >  	 * dereferencing the slot for existing bindings needs to be protected
> >  	 * against memslot updates, specifically so that unbind doesn't race
> >  	 * and free the memslot (kvm_gmem_get_file() will return NULL).
> > -	 *
> > -	 * Since .release is called only when the reference count is zero,
> > -	 * after which file_ref_get() and get_file_active() fail,
> > -	 * kvm_gmem_get_pfn() cannot be using the file concurrently.
> > -	 * file_ref_put() provides a full barrier, and get_file_active() the
> > -	 * matching acquire barrier.
> >  	 */
> >  	mutex_lock(&kvm->slots_lock);
> >  
> >  	filemap_invalidate_lock(inode->i_mapping);
> >  
> > +	/*
> > +	 * Note!  synchronize_srcu() is _not_ needed after nullifying memslot
> > +	 * bindings as slot->gmem.file cannot be set back to a non-null value
> > +	 * without the memslot first being deleted.  I.e. this relies on the
> > +	 * synchronize_srcu_expedited() in kvm_swap_active_memslots() to ensure
> > +	 * kvm_gmem_get_pfn() (which runs with kvm->srcu held for read) can't
> > +	 * grab a reference to slot->gmem.file even if the struct file object
> > +	 * is reallocated.
> 
> Nit:
> 
> Do we need to update the code comment in __kvm_gmem_unbind() from
> 	/*
> 	 * synchronize_srcu(&kvm->srcu) ensured that kvm_gmem_get_pfn()
> 	 * cannot see this memslot.
> 	 */
> to
> 	/*
> 	 * synchronize_srcu_expedited() in kvm_swap_active_memslots() ensured
> 	 * that kvm_gmem_get_pfn() cannot see this memslot.
> 	 */
> 
> to align with the above comment.

How about this?  Because the "rule" is that kvm_gmem_unbind() can only be called
on a memslot that is unreachable, either by synchronizing SRCU after uninstalling
the memslot *or* because the memslot was never installed.  Simply stating that
synchronize_srcu_expedited() makes everything safe isn't the whole story, as it's
specifically synchronzing after removing/deleting/deactivating the slot that
makes this safe.

	/*
	 * Note, the caller is responsible for ensuring the slot is unreachable
	 * before unbinding, e.g. by synchronizing SRCU after deleting the slot.
	 */

> > +	 *
> > +	 * file_ref_put() provides a full barrier, and __get_file_rcu() the
> > +	 * matching acquire barrier, to ensure that kvm_gmem_get_file() (via
> > +	 * __get_file_rcu()) sees refcount==0 or fails the "file reloaded"
> > +	 * check (file != NULL due to nullifying the file pointer here).
> > +	 *
> > +	 * Unlike most other users of get_file_rcu(), where callers don't care
> > +	 * if they race with a write, only that they have a reference to _a_
> > +	 * live file, kvm_gmem_get_pfn() needs to get the exact file that is
> > +	 * associated with the memslot.  Without the aforementioned SRCU
> > +	 * synchronization, the following could happen:
> > +	 *
> > +	 *  CPU0				CPU1
> > +	 *  kvm_gmem_get_pfn()
> > +	 *    f = X (from slot->gmem.file)
> > +	 *					kvm_gmem_release())
> > +	 *					  slot->gmem.file = NULL
> > +	 *
> > +	 *					kvm_set_memory_region()
> > +	 *					  slot deleted
> > +	 *
> > +	 *					kvm_set_memory_region()
> > +	 *					  slot created
> > +	 *					  slot->gmem.file = f (alloc the same object)
> > +	 *
> > +	 *  get_file_active()
> > +	 *    file = f
> > +	 *    file_reloaded = f
> > +	 *
> > +	 * <KVM does weird things with an old memslot+file>
> > +	 *
> > +	 * Obviously KVM would be broken in many places if the synchronization
> > +	 * were omitted, but it's important to note that get_file_active() does
> > +	 * NOT guarantee a reference to the correct file was obtained, only
> > +	 * that the file doesn't point at a reallocated object.
> reallocated -> reloaded?

No, "reallocated" is correct.  From the comment for SLAB_TYPESAFE_BY_RCU:

  * This delays freeing the SLAB page by a grace period, it does _NOT_
  * delay object freeing. This means that if you do kmem_cache_free()
  * that memory location is free to be reused at any time. Thus it may
  * be possible to see another object there in the same RCU grace period.
  *
  * This feature only ensures the memory location backing the object
  * stays valid, the trick to using this is relying on an independent
  * object validation pass. Something like:
  *
  * ::
  *
  *  begin:
  *   rcu_read_lock();
  *   obj = lockless_lookup(key);
  *   if (obj) {
  *     if (!try_get_ref(obj)) // might fail for free objects
  *       rcu_read_unlock();
  *       goto begin;
  *
  *     if (obj->key != key) { // not the object we expected
  *       put_ref(obj);
  *       rcu_read_unlock();
  *       goto begin;
  *     }
  *   }
  *  rcu_read_unlock();

The above pseudocode is what get_file_active() is doing; it verifies the found
file ("obj" above) is the correct file.  Specifically, from __get_file_rcu():

	 * If the pointers don't match the file has been reallocated by
	 * SLAB_TYPESAFE_BY_RCU.

  reply	other threads:[~2026-09-21 13:40 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-26 16:56 [PATCH v2] KVM: guest_memfd: Elaborate on how release() vs. get_pfn() is safe against UAF Sean Christopherson
2026-08-26 17:11 ` sashiko-bot
2026-08-26 18:39   ` Sean Christopherson
2026-09-20 12:55 ` Yan Zhao
2026-09-21 13:40   ` Sean Christopherson [this message]
2026-09-21 13:43     ` Sean Christopherson
2026-09-22  3:47       ` Yan Zhao
2026-09-22  3:45     ` Yan Zhao
2026-09-22 14:22       ` Sean Christopherson
2026-09-23  5:01         ` Yan Zhao
2026-09-24 21:51 ` Sean Christopherson

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=arEzv8b2IMHYcHsZ@google.com \
    --to=seanjc@google.com \
    --cc=david@kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=vannapurve@google.com \
    --cc=yan.y.zhao@intel.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.