[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAGtprH9H7cHAzdTpPrP-H8Z7yWgRFmTtXNjORDJsuq6AKPbnHg@mail.gmail.com>
Date: Tue, 4 Nov 2025 08:57:47 -0800
From: Vishal Annapurve <vannapurve@...gle.com>
To: Sean Christopherson <seanjc@...gle.com>
Cc: Paolo Bonzini <pbonzini@...hat.com>, kvm@...r.kernel.org, linux-kernel@...r.kernel.org,
syzbot+2479e53d0db9b32ae2aa@...kaller.appspotmail.com,
Hillf Danton <hdanton@...a.com>
Subject: Re: [PATCH] KVM: guest_memfd: Remove bindings on memslot deletion
when gmem is dying
On Mon, Nov 3, 2025 at 5:12 PM Sean Christopherson <seanjc@...gle.com> wrote:
>
> Deliberately don't acquire filemap invalid lock when the file is dying as
> the lifecycle of f_mapping is outside the purview of KVM. Dereferencing
> the mapping is *probably* fine, but there's no need to invalidate anything
> as memslot deletion is responsible for zapping SPTEs, and the only code
> that can access the dying file is kvm_gmem_release(), whose core code is
> mutually exclusive with unbinding.
>
> Note, the mutual exclusivity is also what makes it self to access the
^ safe
> bindings on a dying gmem instance. Unbinding either runs with slots_lock
> held, or after the last reference to the owning "struct kvm" is put, and
> kvm_gmem_release() nullifies the slot pointer under slots_lock, and puts
> its reference to the VM after that is done.
>
> Reported-by: syzbot+2479e53d0db9b32ae2aa@...kaller.appspotmail.com
> Closes: https://lore.kernel.org/all/68fa7a22.a70a0220.3bf6c6.008b.GAE@google.com
> Tested-by: syzbot+2479e53d0db9b32ae2aa@...kaller.appspotmail.com
> Fixes: a7800aa80ea4 ("KVM: Add KVM_CREATE_GUEST_MEMFD ioctl() for guest-specific backing memory")
> Cc: stable@...r.kernel.org
> Cc: Hillf Danton <hdanton@...a.com>
> Signed-off-by: Sean Christopherson <seanjc@...gle.com>
Reviewed-By: Vishal Annapurve <vannapurve@...gle.com>
> ---
> virt/kvm/guest_memfd.c | 46 +++++++++++++++++++++++++++++-------------
> 1 file changed, 32 insertions(+), 14 deletions(-)
>
> diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
> index fbca8c0972da..050731922522 100644
> --- a/virt/kvm/guest_memfd.c
> +++ b/virt/kvm/guest_memfd.c
> @@ -623,24 +623,11 @@ int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
> return r;
> }
>
> -void kvm_gmem_unbind(struct kvm_memory_slot *slot)
> +static void __kvm_gmem_unbind(struct kvm_memory_slot *slot, struct kvm_gmem *gmem)
> {
> unsigned long start = slot->gmem.pgoff;
> unsigned long end = start + slot->npages;
> - struct kvm_gmem *gmem;
> - struct file *file;
>
> - /*
> - * Nothing to do if the underlying file was already closed (or is being
> - * closed right now), kvm_gmem_release() invalidates all bindings.
> - */
> - file = kvm_gmem_get_file(slot);
> - if (!file)
> - return;
> -
> - gmem = file->private_data;
> -
> - filemap_invalidate_lock(file->f_mapping);
> xa_store_range(&gmem->bindings, start, end - 1, NULL, GFP_KERNEL);
>
> /*
> @@ -648,6 +635,37 @@ void kvm_gmem_unbind(struct kvm_memory_slot *slot)
> * cannot see this memslot.
> */
> WRITE_ONCE(slot->gmem.file, NULL);
> +}
> +
> +void kvm_gmem_unbind(struct kvm_memory_slot *slot)
> +{
> + struct file *file;
> +
> + /*
> + * Nothing to do if the underlying file was _already_ closed, as
> + * kvm_gmem_release() invalidates and nullifies all bindings.
> + */
> + if (!slot->gmem.file)
> + return;
> +
> + file = kvm_gmem_get_file(slot);
> +
> + /*
> + * However, if the file is _being_ closed, then the bindings need to be
> + * removed as kvm_gmem_release() might not run until after the memslot
> + * is freed. Note, modifying the bindings is safe even though the file
> + * is dying as kvm_gmem_release() nullifies slot->gmem.file under
> + * slots_lock, and only puts its reference to KVM after destroying all
> + * bindings. I.e. reaching this point means kvm_gmem_release() can't
> + * concurrently destroy the bindings or free the gmem_file.
Maybe a bit more description here is warranted:
Reaching this point also means that kvm_gmem_release() hasn't *yet*
freed the private_data or the bindings.
> + */
> + if (!file) {
> + __kvm_gmem_unbind(slot, slot->gmem.file->private_data);
> + return;
> + }
> +
> + filemap_invalidate_lock(file->f_mapping);
> + __kvm_gmem_unbind(slot, file->private_data);
> filemap_invalidate_unlock(file->f_mapping);
>
> fput(file);
>
> base-commit: 4361f5aa8bfcecbab3fc8db987482b9e08115a6a
> --
> 2.51.2.1006.ga50a493c49-goog
>
>
Powered by blists - more mailing lists