From: "David Hildenbrand (Arm)" <david@kernel.org>
To: Sean Christopherson <seanjc@google.com>,
Paolo Bonzini <pbonzini@redhat.com>
Cc: 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: Re: [PATCH v3 3/4] KVM: guest_memfd: Establish memslot<=>guest_memfd bindings *after* memslot is ready
Date: Mon, 7 Sep 2026 19:47:08 +0200 [thread overview]
Message-ID: <b0035ada-8760-4c43-aac5-264d6b1d0099@kernel.org> (raw)
In-Reply-To: <20260904004342.3162959-4-seanjc@google.com>
On 9/4/26 02:43, Sean Christopherson wrote:
> 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) {
For readability I'd throw in an extra pair of (). But KVM seems to use both
styles, so there is no clear preference when staring at the existing code :)
> + 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) {
We'd never end up here with !new, right?
> + kvm_arch_free_memslot(kvm, new);
> +
> + if (new->dirty_bitmap && (!old || !old->dirty_bitmap))
> + kvm_destroy_dirty_bitmap(new);
That's essentially the cleanup path in kvm_prepare_memory_region().
I guess with some more reshuffling we could have a single dirty bitmap cleanup
path in this code.
> + }
> 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;
In general LGTM.
--
Cheers,
David
next prev parent reply other threads:[~2026-09-07 17:47 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-04 0:43 [PATCH v3 0/4] KVM: guest_memfd: Fix binding bugs Sean Christopherson
2026-09-04 0:43 ` [PATCH v3 1/4] KVM: guest_memfd: Gracefully handle xarray errors when binding a memslot Sean Christopherson
2026-09-07 17:34 ` David Hildenbrand (Arm)
2026-09-09 19:27 ` Sean Christopherson
2026-09-09 22:59 ` Ackerley Tng
2026-09-10 0:11 ` Sean Christopherson
2026-09-04 0:43 ` [PATCH v3 2/4] KVM: Use goto to handle errors during memslot preparation Sean Christopherson
2026-09-07 17:36 ` David Hildenbrand (Arm)
2026-09-09 23:09 ` Ackerley Tng
2026-09-04 0:43 ` [PATCH v3 3/4] KVM: guest_memfd: Establish memslot<=>guest_memfd bindings *after* memslot is ready Sean Christopherson
2026-09-07 17:47 ` David Hildenbrand (Arm) [this message]
2026-09-09 21:53 ` Sean Christopherson
2026-09-04 0:43 ` [PATCH v3 4/4] KVM: guest_memfd: Drop superfluous WRITE_ONCE() when binding a memslot Sean Christopherson
2026-09-07 17:47 ` David Hildenbrand (Arm)
2026-09-09 23:06 ` Ackerley Tng
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=b0035ada-8760-4c43-aac5-264d6b1d0099@kernel.org \
--to=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=seanjc@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox