From: sashiko-bot@kernel.org
To: "Sean Christopherson" <seanjc@google.com>
Cc: kvm@vger.kernel.org
Subject: Re: [PATCH v3 04/15] KVM: x86: Unmap VMAs for KVM-internal memslots when the memslot is freed
Date: Tue, 27 Oct 2026 22:27:21 +0000 [thread overview]
Message-ID: <sashiko-outbox-187159@kernel.org> (raw)
In-Reply-To: <20261027221209.1560865-5-seanjc@google.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] KVM: x86: premature VMA unmap in kvm_arch_free_memslot() while SMM slot is active
--
commit 6659f140d07225e838a8f211264ec11bfb5e9df2
Author: Sean Christopherson <seanjc@google.com>
KVM: x86: Unmap VMAs for KVM-internal memslots when the memslot is freed
This commit moves the VMA unmapping for x86 KVM-internal memslots from
__x86_set_memory_region() into kvm_arch_free_memslot(), and removes the
explicit internal memslot teardown from kvm_arch_destroy_vm().
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 32563a91fba99..0f3fa45713097 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
[ ... ]
> @@ -10058,8 +10058,7 @@ void __user * __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa,
> if (!slot || !slot->npages)
> return NULL;
>
> - old_npages = slot->npages;
> - hva = slot->userspace_addr;
> + hva = 0;
> }
>
> for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
> @@ -10075,9 +10074,6 @@ void __user * __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa,
> return ERR_PTR_USR(r);
> }
>
> - if (!size)
> - vm_munmap(hva, old_npages * PAGE_SIZE);
> -
> return (void __user *)hva;
> }
> EXPORT_SYMBOL_FOR_KVM_INTERNAL(__x86_set_memory_region);
[ ... ]
> @@ -10159,6 +10141,18 @@ void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)
> }
>
> kvm_page_track_free_memslot(slot);
> +
> + /*
> + * Unmap VMAs allocated on behalf of userspace for internal memslots,
> + * unless the memory map has changed due to process exit or fd copying.
> + * Do the unmap only for the non-SMM slot, as the same VMA is used for
> + * both non-SMM and SMM memslots. Leak the mapping on failure, e.g.
> + * if the task is killed. Worst case scenario, the page(s) will be
> + * reclaimed when the process exits.
> + */
> + if (current->mm == kvm->mm && slot->id >= KVM_USER_MEM_SLOTS &&
> + !slot->as_id && !WARN_ON_ONCE(!slot->npages))
> + vm_munmap(slot->userspace_addr, slot->npages * PAGE_SIZE);
[Severity: High]
Does unmapping the shared VMA in arch/x86/kvm/x86.c:kvm_arch_free_memslot()
when !slot->as_id cause a premature unmap while the SMM memslot (as_id == 1)
is still active?
When an internal memslot is deleted at runtime while vCPUs are running, such
as via arch/x86/kvm/lapic.c:kvm_inhibit_apic_access_page():
if (kvm->arch.apic_access_memslot_enabled) {
__x86_set_memory_region(kvm, APIC_ACCESS_PAGE_PRIVATE_MEMSLOT, 0, 0);
__x86_set_memory_region() iterates over the address spaces from i = 0 to
kvm_arch_nr_memslot_as_ids(kvm) - 1:
for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
struct kvm_userspace_memory_region2 m;
m.slot = id | (i << 16);
m.flags = 0;
m.guest_phys_addr = gpa;
m.userspace_addr = hva;
m.memory_size = size;
r = kvm_set_internal_memslot(kvm, &m);
if (r < 0)
return ERR_PTR_USR(r);
}
Previously, vm_munmap() was called only after this loop finished deleting the
memslot from all address spaces.
With this change, on iteration i = 0 (as_id == 0), the call chain:
kvm_set_internal_memslot()
-> kvm_set_memory_region()
-> kvm_set_memslot(..., KVM_MR_DELETE)
-> kvm_commit_memory_region()
-> kvm_free_memslot()
-> kvm_arch_free_memslot()
sees !slot->as_id and immediately calls vm_munmap(slot->userspace_addr, ...),
releasing mmap_write_lock before iteration i = 1 begins.
Until iteration i = 1 calls kvm_invalidate_memslot() on the SMM slot, the
memslot in kvm->memslots[1] remains active and valid while pointing to the
already-unmapped userspace_addr. If a vCPU in SMM accesses or faults on that
GPA during this window, couldn't it resolve the active SMM memslot to an
unmapped HVA (failing KVM_RUN with -EFAULT) or to an unrelated VMA if another
host thread concurrently calls mmap()?
In addition, if iteration i = 1 fails in virt/kvm/kvm_main.c:kvm_set_memslot()
when allocating invalid_slot:
if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) {
invalid_slot = kzalloc_obj(*invalid_slot, GFP_KERNEL_ACCOUNT);
if (!invalid_slot) {
mutex_unlock(&kvm->slots_arch_lock);
return -ENOMEM;
}
kvm_invalidate_memslot(kvm, old, invalid_slot);
}
__x86_set_memory_region() aborts after as_id == 0 has already been deleted and
unmapped. Because __x86_set_memory_region() checks id_to_memslot(slots, id) in
as_id == 0 on entry and returns NULL if !slot, wouldn't the SMM memslot in
kvm->memslots[1] be left permanently active with a dangling userspace_addr?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261027221209.1560865-1-seanjc@google.com?part=4
next prev parent reply other threads:[~2026-10-27 22:27 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-27 22:11 [PATCH v3 00/15] KVM: Fix+harden against bad uaccess using dying VM Sean Christopherson
2026-10-27 22:11 ` [PATCH v3 01/15] KVM: Reject user accesses to guest memory if current->mm != kvm->mm Sean Christopherson
2026-10-27 22:11 ` [PATCH v3 02/15] KVM: nVMX: Don't force a full nested VM-Exit when destroying a vCPU Sean Christopherson
2026-10-27 22:54 ` Sean Christopherson
2026-10-27 22:11 ` [PATCH v3 03/15] KVM: PPC: Flush/zap all memslots on kvm_arch_flush_shadow_all() Sean Christopherson
2026-10-27 22:11 ` [PATCH v3 04/15] KVM: x86: Unmap VMAs for KVM-internal memslots when the memslot is freed Sean Christopherson
2026-10-27 22:27 ` sashiko-bot [this message]
2026-10-27 22:11 ` [PATCH v3 05/15] KVM: Disallow setting memslots when the VM is being destroyed Sean Christopherson
2026-10-27 22:11 ` [PATCH v3 06/15] KVM: Destroy memslots immediately after mmu_notifiers are unregistered Sean Christopherson
2026-10-27 22:12 ` [PATCH v3 07/15] KVM: WARN if KVM attempts to do guest-related uaccess with "wrong" process Sean Christopherson
2026-10-27 22:12 ` [PATCH v3 08/15] KVM: WARN and reject guest-based uaccess if VM is dying Sean Christopherson
2026-10-28 0:26 ` James Houghton
2026-10-27 22:12 ` [PATCH v3 09/15] KVM: Pre-check uaccesses in KVM's APIs to read/write guest memory Sean Christopherson
2026-10-28 0:22 ` James Houghton
2026-10-27 22:12 ` [PATCH v3 10/15] KVM: VMX: Explicility free vmcs01, not the current VMCS, in vCPU free paths Sean Christopherson
2026-10-28 0:33 ` James Houghton
2026-10-27 22:12 ` [PATCH v3 11/15] KVM: nVMX: Don't explicitly VMCLEAR+free() vmcs01's shadow VMCS when freeing vCPU Sean Christopherson
2026-10-27 22:12 ` [PATCH v3 12/15] KVM: nVMX: Cancel the nested VMX Preemption Timer's hrtimer in free_nested() Sean Christopherson
2026-10-27 22:12 ` [PATCH v3 13/15] KVM: VMX: Explicitly remove dying vCPUs from the PI wakeup list Sean Christopherson
2026-10-27 22:32 ` sashiko-bot
2026-10-27 22:12 ` [PATCH v3 14/15] KVM: nVMX: Don't switch to vmcs01 when freeing a vCPU Sean Christopherson
2026-10-27 22:12 ` [PATCH v3 15/15] KVM: nVMX: Don't load+put the vCPU when freeing nested state for a dying vCPU Sean Christopherson
2026-10-28 9:18 ` [syzbot ci] Re: KVM: Fix+harden against bad uaccess using dying VM syzbot ci
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=sashiko-outbox-187159@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=kvm@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=seanjc@google.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