* [PATCH v5 1/6] KVM: guest_memfd: Gracefully handle xarray errors when binding a memslot
2026-09-22 0:13 [PATCH v5 0/6] KVM: guest_memfd: Fix binding bugs Sean Christopherson
@ 2026-09-22 0:13 ` Sean Christopherson
2026-09-22 0:13 ` [PATCH v5 2/6] KVM: Use goto to handle errors during memslot preparation Sean Christopherson
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Sean Christopherson @ 2026-09-22 0:13 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: David Hildenbrand, kvm, linux-kernel, Stefan Teodorescu,
Dennis Tighe, Sashiko Bot, Ackerley Tng, Yan Zhao
If inserting a memslot into a guest_memfd's bindings xarray fails,
propagate the error back to the caller, i.e. fail memslot creation as well.
Signalling success and continuing on with memslot creation results in
use-after-free, as the guest_memfd instance will remain reachable via the
memslot after the file is freed (kvm_gmem_release() won't nullify the file
pointer due to lack of a valid binding).
Opportunistically WARN and reject binding if KVM_MEMSLOT_GMEM_ONLY is
already set, partly to guard against goofs elsewhere, but mostly so that
KVM doesn't need to worry about clobbering flags when unwinding on failure.
Regarding the unwind, the slot must be fully prepared before inserting it
into the bindings, at which point the slot becomes reachable. I.e. waiting
to update the slot in order to avoid the ugly unwind isn't an option. And
as part of the unwind, explicitly nullify the relevant bindings, as xarray
can store a subset of entries when populating a range.
Fixes: a7800aa80ea4 ("KVM: Add KVM_CREATE_GUEST_MEMFD ioctl() for guest-specific backing memory")
Cc: stable@vger.kernel.org
Reported-by: Stefan Teodorescu <fane@google.com>
Reported-by: Dennis Tighe <dtighe@google.com>
Reported-by: Sashiko Bot <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260823135031.4F6DC1F000E9%40smtp.kernel.org
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Ackerley Tng <ackerleytng@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
virt/kvm/guest_memfd.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 63943aa253d4..c094611f7c7a 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -654,6 +654,9 @@ int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
BUILD_BUG_ON(sizeof(gpa_t) != sizeof(offset));
BUILD_BUG_ON(sizeof(gfn_t) != sizeof(slot->gmem.pgoff));
+ if (WARN_ON_ONCE(slot->flags & KVM_MEMSLOT_GMEM_ONLY))
+ return -EINVAL;
+
file = fget(fd);
if (!file)
return -EBADF;
@@ -692,7 +695,13 @@ int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
if (kvm_gmem_supports_mmap(inode))
slot->flags |= KVM_MEMSLOT_GMEM_ONLY;
- xa_store_range(&f->bindings, start, end - 1, slot, GFP_KERNEL);
+ r = xa_err(xa_store_range(&f->bindings, start, end - 1, slot, GFP_KERNEL));
+ if (r) {
+ xa_store_range(&f->bindings, start, end - 1, NULL, GFP_KERNEL);
+ slot->gmem.file = NULL;
+ slot->gmem.pgoff = 0;
+ slot->flags &= ~KVM_MEMSLOT_GMEM_ONLY;
+ }
filemap_invalidate_unlock(inode->i_mapping);
/*
@@ -700,7 +709,6 @@ int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
* not the other way 'round. Active bindings are invalidated if the
* file is closed before memslots are destroyed.
*/
- r = 0;
err:
fput(file);
return r;
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v5 2/6] KVM: Use goto to handle errors during memslot preparation
2026-09-22 0:13 [PATCH v5 0/6] KVM: guest_memfd: Fix binding bugs Sean Christopherson
2026-09-22 0:13 ` [PATCH v5 1/6] KVM: guest_memfd: Gracefully handle xarray errors when binding a memslot Sean Christopherson
@ 2026-09-22 0:13 ` Sean Christopherson
2026-09-22 0:13 ` [PATCH v5 3/6] KVM: Only bind memslot to guest_memfd instance for CREATE operations Sean Christopherson
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Sean Christopherson @ 2026-09-22 0:13 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: David Hildenbrand, kvm, linux-kernel, Stefan Teodorescu,
Dennis Tighe, Sashiko Bot, Ackerley Tng, Yan Zhao
Use a goto to unwind early memslot changes if preparing for a memslot
operation fails. This will allow moving the creation of guest_memfd
bindings into kvm_set_memslot() without needing to copy+paste the unwind
logic.
No functional change intended.
Cc: stable@vger.kernel.org
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Ackerley Tng <ackerleytng@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
virt/kvm/kvm_main.c | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index d9da8b51614a..24cf96840827 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1941,21 +1941,8 @@ static int kvm_set_memslot(struct kvm *kvm,
}
r = kvm_prepare_memory_region(kvm, old, new, change);
- if (r) {
- /*
- * For DELETE/MOVE, revert the above INVALID change. No
- * modifications required since the original slot was preserved
- * in the inactive slots. Changing the active memslots also
- * release slots_arch_lock.
- */
- if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) {
- kvm_activate_memslot(kvm, invalid_slot, old);
- kfree(invalid_slot);
- } else {
- mutex_unlock(&kvm->slots_arch_lock);
- }
- return r;
- }
+ if (r)
+ goto err;
/*
* For DELETE and MOVE, the working slot is now active as the INVALID
@@ -1987,6 +1974,20 @@ static int kvm_set_memslot(struct kvm *kvm,
kvm_commit_memory_region(kvm, old, new, change);
return 0;
+
+err:
+ /*
+ * For DELETE/MOVE, revert the above INVALID change. No modifications
+ * required since the original slot was preserved in the inactive slots.
+ * Changing the active memslots also release slots_arch_lock.
+ */
+ if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) {
+ kvm_activate_memslot(kvm, invalid_slot, old);
+ kfree(invalid_slot);
+ } else {
+ mutex_unlock(&kvm->slots_arch_lock);
+ }
+ return r;
}
static bool kvm_check_memslot_overlap(struct kvm_memslots *slots, int id,
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v5 3/6] KVM: Only bind memslot to guest_memfd instance for CREATE operations
2026-09-22 0:13 [PATCH v5 0/6] KVM: guest_memfd: Fix binding bugs Sean Christopherson
2026-09-22 0:13 ` [PATCH v5 1/6] KVM: guest_memfd: Gracefully handle xarray errors when binding a memslot Sean Christopherson
2026-09-22 0:13 ` [PATCH v5 2/6] KVM: Use goto to handle errors during memslot preparation Sean Christopherson
@ 2026-09-22 0:13 ` Sean Christopherson
2026-09-22 8:15 ` David Hildenbrand (Arm)
2026-09-22 0:13 ` [PATCH v5 4/6] KVM: guest_memfd: Split bind() into prepare()+commit() phases Sean Christopherson
` (2 subsequent siblings)
5 siblings, 1 reply; 8+ messages in thread
From: Sean Christopherson @ 2026-09-22 0:13 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: David Hildenbrand, kvm, linux-kernel, Stefan Teodorescu,
Dennis Tighe, Sashiko Bot, Ackerley Tng, Yan Zhao
For additional defense-in-depth, and to avoid having to handle impossible
unwind scenarios when binding to a memslot fails, bind a memslot to a gmem
instance only when for CREATE operations, i.e. don't attempt to establish a
binding for MOVE and FLAGS_ONLY operations. And when FLAGS_ONLY operations
are eventually supported (this is currently all dead code), creating a new
binding would be incorrect; KVM instead needs to do a 1:1 replacement of
the existing binding, i.e. FLAGS_ONLY will need its own dedicated handling.
Update the relevant TODO to make a better guess as to what needs to be done
to support toggling dirty logging for guest_memfd memslots.
Because it's dead code, no functional change intended.
Cc: stable@vger.kernel.org
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
virt/kvm/kvm_main.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 24cf96840827..ccfd5f5102a5 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1752,10 +1752,10 @@ static void kvm_commit_memory_region(struct kvm *kvm,
kvm_destroy_dirty_bitmap(old);
/*
- * Unbind the guest_memfd instance as needed; the @new slot has
- * already created its own binding. TODO: Drop the WARN when
- * dirty logging guest_memfd memslots is supported. Until then,
- * flags-only changes on guest_memfd slots should be impossible.
+ * TODO: Drop the WARN and do the unbind() call only for MOVE
+ * when dirty logging guest_memfd memslots is supported. Until
+ * then, flags-only changes on guest_memfd slots should also be
+ * impossible; unbind the old memslot for defense-in-depth.
*/
if (WARN_ON_ONCE(old->flags & KVM_MEM_GUEST_MEMFD))
kvm_gmem_unbind(old);
@@ -2116,7 +2116,7 @@ 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) {
+ if (change == KVM_MR_CREATE && (mem->flags & KVM_MEM_GUEST_MEMFD)) {
r = kvm_gmem_bind(kvm, new, mem->guest_memfd, mem->guest_memfd_offset);
if (r)
goto out;
@@ -2129,7 +2129,7 @@ static int kvm_set_memory_region(struct kvm *kvm,
return 0;
out_unbind:
- if (mem->flags & KVM_MEM_GUEST_MEMFD)
+ if (change == KVM_MR_CREATE && (mem->flags & KVM_MEM_GUEST_MEMFD))
kvm_gmem_unbind(new);
out:
kfree(new);
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH v5 3/6] KVM: Only bind memslot to guest_memfd instance for CREATE operations
2026-09-22 0:13 ` [PATCH v5 3/6] KVM: Only bind memslot to guest_memfd instance for CREATE operations Sean Christopherson
@ 2026-09-22 8:15 ` David Hildenbrand (Arm)
0 siblings, 0 replies; 8+ messages in thread
From: David Hildenbrand (Arm) @ 2026-09-22 8:15 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Stefan Teodorescu, Dennis Tighe, Sashiko Bot,
Ackerley Tng, Yan Zhao
On 9/22/26 02:13, Sean Christopherson wrote:
> For additional defense-in-depth, and to avoid having to handle impossible
> unwind scenarios when binding to a memslot fails, bind a memslot to a gmem
> instance only when for CREATE operations, i.e. don't attempt to establish a
s/when for/for/
> binding for MOVE and FLAGS_ONLY operations. And when FLAGS_ONLY operations
> are eventually supported (this is currently all dead code), creating a new
> binding would be incorrect; KVM instead needs to do a 1:1 replacement of
> the existing binding, i.e. FLAGS_ONLY will need its own dedicated handling.
>
> Update the relevant TODO to make a better guess as to what needs to be done
> to support toggling dirty logging for guest_memfd memslots.
>
> Because it's dead code, no functional change intended.
>
> Cc: stable@vger.kernel.org
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
--
Cheers,
David
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v5 4/6] KVM: guest_memfd: Split bind() into prepare()+commit() phases
2026-09-22 0:13 [PATCH v5 0/6] KVM: guest_memfd: Fix binding bugs Sean Christopherson
` (2 preceding siblings ...)
2026-09-22 0:13 ` [PATCH v5 3/6] KVM: Only bind memslot to guest_memfd instance for CREATE operations Sean Christopherson
@ 2026-09-22 0:13 ` Sean Christopherson
2026-09-22 0:13 ` [PATCH v5 5/6] KVM: guest_memfd: Establish memslot<=>guest_memfd bindings *after* memslot is ready Sean Christopherson
2026-09-22 0:13 ` [PATCH v5 6/6] KVM: guest_memfd: Drop superfluous WRITE_ONCE() when binding a memslot Sean Christopherson
5 siblings, 0 replies; 8+ messages in thread
From: Sean Christopherson @ 2026-09-22 0:13 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: David Hildenbrand, kvm, linux-kernel, Stefan Teodorescu,
Dennis Tighe, Sashiko Bot, Ackerley Tng, Yan Zhao
Split binding a memslot to a guest_memfd instance into prepare() and
commit() phases so that KVM can separate preparing the memslot from binding
the memslot to the gmem instance, i.e. from committing the memslot. This
will allow waiting to commit the memslot+gmem binding until the memslot is
fully prepared, which is necessary as the memslot becomes reachable when
the binding is created.
As a bonus, drop the unwind-on-failure from the commit phase (other than
nullifying the bindings), as the only reason bind() did the full unwind is
because it technically didn't own the memslot, i.e. "needed" to leave
memslot in the same state it started in.
No functional change intended (the unwinding down on bind() failure was
effectively dead code since KVM simply deletes the memslot on failure,
i.e. there was nothing that could actually observe the unwind).
Cc: stable@vger.kernel.org
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
virt/kvm/guest_memfd.c | 68 ++++++++++++++++++++++++------------------
virt/kvm/guest_memfd.h | 19 ++++++++----
virt/kvm/kvm_main.c | 18 ++++++++++-
3 files changed, 70 insertions(+), 35 deletions(-)
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index c094611f7c7a..80932f4ec4a3 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -641,15 +641,14 @@ int kvm_gmem_create(struct kvm *kvm, struct kvm_create_guest_memfd *args)
return __kvm_gmem_create(kvm, size, flags);
}
-int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
- unsigned int fd, uoff_t offset)
+int kvm_gmem_prepare_memory_region(struct kvm *kvm, struct kvm_memory_slot *slot,
+ unsigned int fd, uoff_t offset)
{
uoff_t size = slot->npages << PAGE_SHIFT;
- unsigned long start, end;
struct gmem_file *f;
struct inode *inode;
struct file *file;
- int r = -EINVAL;
+
BUILD_BUG_ON(sizeof(gpa_t) != sizeof(offset));
BUILD_BUG_ON(sizeof(gfn_t) != sizeof(slot->gmem.pgoff));
@@ -673,44 +672,55 @@ int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
if (!PAGE_ALIGNED(offset) || offset + size > i_size_read(inode))
goto err;
- filemap_invalidate_lock(inode->i_mapping);
-
- start = offset >> PAGE_SHIFT;
- end = start + slot->npages;
-
- if (!xa_empty(&f->bindings) &&
- xa_find(&f->bindings, &start, end - 1, XA_PRESENT)) {
- r = -EEXIST;
- filemap_invalidate_unlock(inode->i_mapping);
- goto err;
- }
-
/*
* memslots of flag KVM_MEM_GUEST_MEMFD are immutable to change, so
* kvm_gmem_bind() must occur on a new memslot. Because the memslot
* is not visible yet, kvm_gmem_get_pfn() is guaranteed to see the file.
*/
WRITE_ONCE(slot->gmem.file, file);
- slot->gmem.pgoff = start;
+ slot->gmem.pgoff = offset >> PAGE_SHIFT;
if (kvm_gmem_supports_mmap(inode))
slot->flags |= KVM_MEMSLOT_GMEM_ONLY;
- r = xa_err(xa_store_range(&f->bindings, start, end - 1, slot, GFP_KERNEL));
- if (r) {
- xa_store_range(&f->bindings, start, end - 1, NULL, GFP_KERNEL);
- slot->gmem.file = NULL;
- slot->gmem.pgoff = 0;
- slot->flags &= ~KVM_MEMSLOT_GMEM_ONLY;
- }
- filemap_invalidate_unlock(inode->i_mapping);
-
/*
- * Drop the reference to the file, even on success. The file pins KVM,
- * not the other way 'round. Active bindings are invalidated if the
- * file is closed before memslots are destroyed.
+ * Gift the caller a reference to the file. The reference will be
+ * dropped after bindings are established, or if installing the new
+ * memslot ultimately fails.
*/
+ return 0;
+
err:
fput(file);
+ return -EINVAL;
+}
+
+int kvm_gmem_commit_memory_region(struct kvm *kvm, struct kvm_memory_slot *slot)
+{
+ struct gmem_file *f = slot->gmem.file->private_data;
+ struct inode *inode = file_inode(slot->gmem.file);
+ unsigned long start, end;
+ int r;
+
+ if (WARN_ON_ONCE(slot->gmem.file->f_op != &kvm_gmem_fops))
+ return -EIO;
+
+ filemap_invalidate_lock(inode->i_mapping);
+
+ start = slot->gmem.pgoff;
+ end = start + slot->npages;
+
+ if (!xa_empty(&f->bindings) &&
+ xa_find(&f->bindings, &start, end - 1, XA_PRESENT)) {
+ filemap_invalidate_unlock(inode->i_mapping);
+ return -EEXIST;
+ }
+
+ r = xa_err(xa_store_range(&f->bindings, start, end - 1, slot, GFP_KERNEL));
+ if (r)
+ xa_store_range(&f->bindings, start, end - 1, NULL, GFP_KERNEL);
+
+ filemap_invalidate_unlock(inode->i_mapping);
+
return r;
}
diff --git a/virt/kvm/guest_memfd.h b/virt/kvm/guest_memfd.h
index 0f9c6f840838..01bd359d27e3 100644
--- a/virt/kvm/guest_memfd.h
+++ b/virt/kvm/guest_memfd.h
@@ -8,8 +8,9 @@
int kvm_gmem_init(struct module *module);
void kvm_gmem_exit(void);
int kvm_gmem_create(struct kvm *kvm, struct kvm_create_guest_memfd *args);
-int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
- unsigned int fd, uoff_t offset);
+int kvm_gmem_prepare_memory_region(struct kvm *kvm, struct kvm_memory_slot *slot,
+ unsigned int fd, uoff_t offset);
+int kvm_gmem_commit_memory_region(struct kvm *kvm, struct kvm_memory_slot *slot);
void kvm_gmem_unbind(struct kvm_memory_slot *slot);
#else
static inline int kvm_gmem_init(struct module *module)
@@ -17,9 +18,17 @@ static inline int kvm_gmem_init(struct module *module)
return 0;
}
static inline void kvm_gmem_exit(void) {};
-static inline int kvm_gmem_bind(struct kvm *kvm,
- struct kvm_memory_slot *slot,
- unsigned int fd, uoff_t offset)
+
+static inline int kvm_gmem_prepare_memory_region(struct kvm *kvm,
+ struct kvm_memory_slot *slot,
+ unsigned int fd, uoff_t offset)
+{
+ WARN_ON_ONCE(1);
+ return -EIO;
+}
+
+static inline int kvm_gmem_commit_memory_region(struct kvm *kvm,
+ struct kvm_memory_slot *slot)
{
WARN_ON_ONCE(1);
return -EIO;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index ccfd5f5102a5..45b509f4e54b 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2117,7 +2117,23 @@ static int kvm_set_memory_region(struct kvm *kvm,
new->flags = mem->flags;
new->userspace_addr = mem->userspace_addr;
if (change == KVM_MR_CREATE && (mem->flags & KVM_MEM_GUEST_MEMFD)) {
- r = kvm_gmem_bind(kvm, new, mem->guest_memfd, mem->guest_memfd_offset);
+ r = kvm_gmem_prepare_memory_region(kvm, new, mem->guest_memfd,
+ mem->guest_memfd_offset);
+ if (r)
+ goto out;
+
+ r = kvm_gmem_commit_memory_region(kvm, new);
+
+ /*
+ * Drop the reference to the file, even on success. The file
+ * pins KVM, not the other way 'round. Active bindings are
+ * invalidated if the file is closed before memslots are
+ * destroyed.
+ */
+#ifdef CONFIG_KVM_GUEST_MEMFD
+ fput(new->gmem.file);
+#endif
+
if (r)
goto out;
}
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v5 5/6] KVM: guest_memfd: Establish memslot<=>guest_memfd bindings *after* memslot is ready
2026-09-22 0:13 [PATCH v5 0/6] KVM: guest_memfd: Fix binding bugs Sean Christopherson
` (3 preceding siblings ...)
2026-09-22 0:13 ` [PATCH v5 4/6] KVM: guest_memfd: Split bind() into prepare()+commit() phases Sean Christopherson
@ 2026-09-22 0:13 ` Sean Christopherson
2026-09-22 0:13 ` [PATCH v5 6/6] KVM: guest_memfd: Drop superfluous WRITE_ONCE() when binding a memslot Sean Christopherson
5 siblings, 0 replies; 8+ messages in thread
From: Sean Christopherson @ 2026-09-22 0:13 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: David Hildenbrand, kvm, linux-kernel, Stefan Teodorescu,
Dennis Tighe, Sashiko Bot, Ackerley Tng, Yan Zhao
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().
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 | 44 +++++++++++++++++++++++---------------------
1 file changed, 23 insertions(+), 21 deletions(-)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 45b509f4e54b..90461880ff85 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1944,6 +1944,15 @@ static int kvm_set_memslot(struct kvm *kvm,
if (r)
goto err;
+ if (change == KVM_MR_CREATE && (new->flags & KVM_MEM_GUEST_MEMFD)) {
+ r = kvm_gmem_commit_memory_region(kvm, new);
+ if (r) {
+ kvm_arch_free_memslot(kvm, new);
+ kvm_destroy_dirty_bitmap(new);
+ goto err;
+ }
+ }
+
/*
* 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
@@ -2121,32 +2130,25 @@ static int kvm_set_memory_region(struct kvm *kvm,
mem->guest_memfd_offset);
if (r)
goto out;
-
- r = kvm_gmem_commit_memory_region(kvm, new);
-
- /*
- * Drop the reference to the file, even on success. The file
- * pins KVM, not the other way 'round. Active bindings are
- * invalidated if the file is closed before memslots are
- * destroyed.
- */
-#ifdef CONFIG_KVM_GUEST_MEMFD
- fput(new->gmem.file);
-#endif
-
- if (r)
- goto out;
}
r = kvm_set_memslot(kvm, old, new, change);
- if (r)
- goto out_unbind;
- return 0;
-
-out_unbind:
+ /*
+ * Drop the reference to the gmem file, even on success. The file pins
+ * KVM, not the other way 'round. Active bindings are invalidated if
+ * the file is closed before memslots are destroyed.
+ */
+#ifdef CONFIG_KVM_GUEST_MEMFD
if (change == KVM_MR_CREATE && (mem->flags & KVM_MEM_GUEST_MEMFD))
- kvm_gmem_unbind(new);
+ fput(new->gmem.file);
+#endif
+
+ if (r)
+ goto out;
+
+ return 0;
+
out:
kfree(new);
return r;
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v5 6/6] KVM: guest_memfd: Drop superfluous WRITE_ONCE() when binding a memslot
2026-09-22 0:13 [PATCH v5 0/6] KVM: guest_memfd: Fix binding bugs Sean Christopherson
` (4 preceding siblings ...)
2026-09-22 0:13 ` [PATCH v5 5/6] KVM: guest_memfd: Establish memslot<=>guest_memfd bindings *after* memslot is ready Sean Christopherson
@ 2026-09-22 0:13 ` Sean Christopherson
5 siblings, 0 replies; 8+ messages in thread
From: Sean Christopherson @ 2026-09-22 0:13 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: David Hildenbrand, kvm, linux-kernel, Stefan Teodorescu,
Dennis Tighe, Sashiko Bot, Ackerley Tng, Yan Zhao
Drop the superfluous WRITE_ONCE() when setting a memslot's guest_memfd file
during initial binding, as the memslot *must* be inactive and unreachable.
The superfluous WRITE_ONCE() was added by commit 67b43038ce14 ("KVM:
guest_memfd: Remove RCU-protected attribute from slot->gmem.file") to
maintain rough "parity" with the existing rcu_assign_pointer(), not
realizing that the only reason rcu_assign_pointer() was used was to make
sparse and other checkers happy.
Cc: Yan Zhao <yan.y.zhao@intel.com>
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Reviewed-by: Ackerley Tng <ackerleytng@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
virt/kvm/guest_memfd.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
index 80932f4ec4a3..826d26036926 100644
--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -677,7 +677,7 @@ int kvm_gmem_prepare_memory_region(struct kvm *kvm, struct kvm_memory_slot *slot
* kvm_gmem_bind() must occur on a new memslot. Because the memslot
* is not visible yet, kvm_gmem_get_pfn() is guaranteed to see the file.
*/
- WRITE_ONCE(slot->gmem.file, file);
+ slot->gmem.file = file;
slot->gmem.pgoff = offset >> PAGE_SHIFT;
if (kvm_gmem_supports_mmap(inode))
slot->flags |= KVM_MEMSLOT_GMEM_ONLY;
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 8+ messages in thread