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,
Stefan Teodorescu <fane@google.com>,
Dennis Tighe <dtighe@google.com>,
Sashiko Bot <sashiko-bot@kernel.org>,
Yan Zhao <yan.y.zhao@intel.com>
Subject: [PATCH v2 3/4] KVM: guest_memfd: Establish memslot<=>guest_memfd bindings *after* memslot is ready
Date: Wed, 2 Sep 2026 11:20:19 -0700 [thread overview]
Message-ID: <20260902182020.2615443-4-seanjc@google.com> (raw)
In-Reply-To: <20260902182020.2615443-1-seanjc@google.com>
Wait to bind a memslot to a guest_memfd instance until *after* the memslot
is fully prepared, as creating the binding in guest_memfd will effectively
expose the memslot to readers. As pointed out by Sashiko, binding the
memslot before it's ready to be exposed to the rest of the world can break
various memslot assumption and rules. E.g. x86 could observe a NULL rmap
pointer if a PUNCH_HOLE hit the guest_memfd after the binding was created,
but before KVM made it through kvm_prepare_memory_region().
Begrudgingly resort to passing in the guest_memfd fd+offset pair to
kvm_set_memslot(), as creating the binding really does need to happen in
the middle of setting the new memslot. Alternatively, to preserve the
aesthetically pleasing function prototype, "struct kvm_memory_slot" could
be expanded to track the fd and the file, but that would create the
possibility for TOCTOU bugs on the fd vs. file, and would add zero value
beyond making kvm_set_memslot() look pretty.
Fixes:a7800aa80ea4 ("KVM: Add KVM_CREATE_GUEST_MEMFD ioctl() for guest-specific backing memory")
Cc: stable@vger.kernel.org
Reported-by: Sashiko Bot <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260826170551.BEF801F000E9@smtp.kernel.org
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
virt/kvm/kvm_main.c | 34 ++++++++++++++++++++++------------
1 file changed, 22 insertions(+), 12 deletions(-)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 3c0dbe60a5b4..21c10cbbac66 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1887,7 +1887,8 @@ static void kvm_update_flags_memslot(struct kvm *kvm,
static int kvm_set_memslot(struct kvm *kvm,
struct kvm_memory_slot *old,
struct kvm_memory_slot *new,
- enum kvm_mr_change change)
+ enum kvm_mr_change change,
+ unsigned int gmem_fd, uoff_t gmem_offset)
{
struct kvm_memory_slot *invalid_slot;
int r;
@@ -1934,6 +1935,15 @@ static int kvm_set_memslot(struct kvm *kvm,
if (r)
goto err;
+ if (new && new->flags & KVM_MEM_GUEST_MEMFD) {
+ if (WARN_ON_ONCE(change != KVM_MR_CREATE))
+ goto err_bind;
+
+ r = kvm_gmem_bind(kvm, new, gmem_fd, gmem_offset);
+ if (r)
+ goto err_bind;
+ }
+
/*
* For DELETE and MOVE, the working slot is now active as the INVALID
* version of the old slot. MOVE is particularly special as it reuses
@@ -1965,6 +1975,13 @@ static int kvm_set_memslot(struct kvm *kvm,
return 0;
+err_bind:
+ if (new) {
+ kvm_arch_free_memslot(kvm, new);
+
+ if (new->dirty_bitmap && (!old || !old->dirty_bitmap))
+ kvm_destroy_dirty_bitmap(new);
+ }
err:
/*
* For DELETE/MOVE, revert the above INVALID change. No modifications
@@ -2059,7 +2076,7 @@ static int kvm_set_memory_region(struct kvm *kvm,
if (WARN_ON_ONCE(kvm->nr_memslot_pages < old->npages))
return -EIO;
- return kvm_set_memslot(kvm, old, NULL, KVM_MR_DELETE);
+ return kvm_set_memslot(kvm, old, NULL, KVM_MR_DELETE, -1, 0);
}
base_gfn = (mem->guest_phys_addr >> PAGE_SHIFT);
@@ -2106,21 +2123,14 @@ static int kvm_set_memory_region(struct kvm *kvm,
new->npages = npages;
new->flags = mem->flags;
new->userspace_addr = mem->userspace_addr;
- if (mem->flags & KVM_MEM_GUEST_MEMFD) {
- r = kvm_gmem_bind(kvm, new, mem->guest_memfd, mem->guest_memfd_offset);
- if (r)
- goto out;
- }
- r = kvm_set_memslot(kvm, old, new, change);
+ r = kvm_set_memslot(kvm, old, new, change,
+ mem->guest_memfd, mem->guest_memfd_offset);
if (r)
- goto out_unbind;
+ goto out;
return 0;
-out_unbind:
- if (mem->flags & KVM_MEM_GUEST_MEMFD)
- kvm_gmem_unbind(new);
out:
kfree(new);
return r;
--
2.55.0.970.g62bdec98f9-goog
next prev parent reply other threads:[~2026-09-02 18:20 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-02 18:20 [PATCH v2 0/4] KVM: guest_memfd: Fix binding bugs Sean Christopherson
2026-09-02 18:20 ` [PATCH v2 1/4] KVM: guest_memfd: Gracefully handle xarray errors when binding a memslot Sean Christopherson
2026-09-02 18:32 ` sashiko-bot
2026-09-02 18:20 ` [PATCH v2 2/4] KVM: Use goto to handle errors during memslot preparation Sean Christopherson
2026-09-02 18:20 ` Sean Christopherson [this message]
2026-09-02 18:35 ` [PATCH v2 3/4] KVM: guest_memfd: Establish memslot<=>guest_memfd bindings *after* memslot is ready sashiko-bot
2026-09-02 18:20 ` [PATCH v2 4/4] KVM: guest_memfd: Drop superfluous WRITE_ONCE() when binding a memslot Sean Christopherson
2026-09-02 18:36 ` sashiko-bot
2026-09-02 19:00 ` 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=20260902182020.2615443-4-seanjc@google.com \
--to=seanjc@google.com \
--cc=david@kernel.org \
--cc=dtighe@google.com \
--cc=fane@google.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=sashiko-bot@kernel.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox