From: Sean Christopherson <seanjc@google.com>
To: Sean Christopherson <seanjc@google.com>,
Paolo Bonzini <pbonzini@redhat.com>
Cc: David Hildenbrand <david@kernel.org>,
kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
Yan Zhao <yan.y.zhao@intel.com>,
Vishal Annapurve <vannapurve@google.com>
Subject: [PATCH v2] KVM: guest_memfd: Elaborate on how release() vs. get_pfn() is safe against UAF
Date: Wed, 26 Aug 2026 09:56:47 -0700 [thread overview]
Message-ID: <20260826165647.769231-1-seanjc@google.com> (raw)
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.
+ *
+ * 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.
+ */
xa_for_each(&f->bindings, index, slot)
WRITE_ONCE(slot->gmem.file, NULL);
base-commit: 76671054f9a1ff6abb976583cd8da37650acdc97
--
2.55.0.887.g758fc8c411-goog
next reply other threads:[~2026-08-26 16:56 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-26 16:56 Sean Christopherson [this message]
2026-08-26 17:11 ` [PATCH v2] KVM: guest_memfd: Elaborate on how release() vs. get_pfn() is safe against UAF sashiko-bot
2026-08-26 18:39 ` Sean Christopherson
2026-09-20 12:55 ` Yan Zhao
2026-09-21 13:40 ` Sean Christopherson
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=20260826165647.769231-1-seanjc@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.