Kernel KVM virtualization development
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: Madhavan Srinivasan <maddy@linux.ibm.com>,
	Sean Christopherson <seanjc@google.com>,
	 Paolo Bonzini <pbonzini@redhat.com>
Cc: Nicholas Piggin <npiggin@gmail.com>,
	linuxppc-dev@lists.ozlabs.org, kvm@vger.kernel.org,
	 linux-kernel@vger.kernel.org, Jim Mattson <jmattson@google.com>,
	 James Houghton <jthoughton@google.com>,
	Chris Mason <mason@kernel.org>
Subject: [PATCH v4 00/23] KVM: Fix+harden against bad uaccess using dying VM
Date: Fri, 30 Oct 2026 14:20:48 -0700	[thread overview]
Message-ID: <20261030212112.2598640-1-seanjc@google.com> (raw)

Stupid SMM.  Patches 1-3 need to go to 7.4, everything else can and should wait.

Fix a class of bugs (limited to nested VMX, as far as we know) where KVM can
corrupt an unrelated process' memory if KVM (attempts to) write to guest memory
during VM destruction.  Because current->mm usually isn't kvm->mm when a VM is
dying, e.g. because the associated kvm->mm process has already exited, writing
to what KVM thinks is guest memory will corrupt the current address space if
the associated userspace address happens to be writable in the victim.

Patch 1 is a blanket fix for the uaccess paths.  AFAIK, x86's nVMX is the only
path in KVM that screws up, but auditing kvm_arch_destroy_vm() proved to be
infeasible for a human (I didn't throw AI at it, yet...), and I can't think of
any downsides to going straight to a broader fix.

Patch 2 fixes the underlyihng nVMX bug where KVM absuses the architectural
nested VM-Exit flow when tearing down a vCPU, which has a truly absurd number
of problems.

Patch 3 fixes what I assume is a blatant PPC bug.  KVM PPC completely ignores
kvm_arch_flush_shadow_all(), i.e. AFAICT, doesn't tear down its page tables
when the owning process exits.  I don't have much confidence in the "fix", in
part because it seems impossible that such a blatant bug could have gone
unnoticed, but also because I went with a very naive approach of invoking
kvm_arch_flush_shadow_memslot() for each memslot.  The changelog is pretty
sparse, because I didn't know how to describe the issue byeond "this is
completely broken".

Patches 4-(I lost track and stopped caring) implement more agressive hardening
to nuke the memslots before calling kvm_arch_destroy_vm(), e.g. to guard
against writing to guest memory during kvm_arch_destroy_vm() without going
through uaccess.  The big pain in the ass is x86's SMM, or more specifically
x86's internal memslots colliding with SMM, where each internal memslot is
actual *two* internal memslots.  KVM currently uses a single VMA for both,
which means KVM can't automatically unmap the VMA when the memslot is freed
without relying on arbitrary ordering.  And there are several other bugs in
the related code.

Setting dummy memslots feels a little hacky, but kvm_arch_flush_shadow_all()
should have purged everything that effectively caches memslots, so it seems
like the right approach?

Patches after that add more hardening to detect KVM bugs (though the
uaccess+memslot changes earlier in the series should render any bugs benign).

The remaining patches double down on open coding nVMX's vCPU teardown by
tearing down the vCPU "as-is", instead of forcing a switch to L1 and then
doing teardown.  The forced switch is quite heinous, as it requires KVM to
*load* the vCPU when it's dying due to architectural constraints for active
VMCSes.  Not only is that gross, it was also papering over a bug (hopefully
just the one) where KVM was relying on the vCPU load for nested VMX to take
vCPUs off the posted interrupts wakeup list.

v4:
 - Fix the SMM+internal memslots issues. [Sashiko]
 - Massage the vt_vcpu_pi_remove_from_wakeup_list() WARN so that it isn't
   triggered if creating a vCPU fails. [Sashiko]
 - Use "unsigned long" instead of "int" for kvm_is_guest_access_ok() params.
   [James]
 - Collect reviews. [James]

v3:
 - Give up, and open code nVMX teardown. [Sashiko, syzbot, Chris]
 - Drop the nVMX hacks that were trying to fudge around the mass of nVMX
   teardown issues.
 - Free the VMA only for the non-SMM internal memslot. [Sashiko]
 - Use @len, not hardcoded PAGE_SIZE, in kvm_is_guest_access_ok(). [Sashiko]
 - Rip out the awful vCPU load code from nested_vmx_free_vcpu().
 - Collect James' reviews.

v2: https://lore.kernel.org/all/20261001202234.3794060-1-seanjc@google.com

v1: https://lore.kernel.org/all/20260908132838.2116068-1-jmattson@google.com

Sean Christopherson (23):
  KVM: Reject user accesses to guest memory if current->mm != kvm->mm
  KVM: nVMX: Don't force a full nested VM-Exit when destroying a vCPU
  KVM: PPC: Flush/zap all memslots on kvm_arch_flush_shadow_all()
  KVM: x86: Drop dead check on an existing memslot not having any pages
  KVM: WARN and error out if memslot update encounters existing slot
    with no pages
  KVM: x86: Unmap VMAs for KVM-internal memslots when the memslot is
    freed
  KVM: x86: Delete non-SMM internal memslot if creating SMM memslot
    fails
  KVM: x86: Process all address spaces when deleting internal memslot
  KVM: x86: Re-queue APICv update request if inhibiting APIC access page
    fails
  KVM: x86: Map a separate VMA for each address space for internal
    memslots
  KVM: Disallow setting memslots when the VM is being destroyed
  KVM: Destroy memslots immediately after mmu_notifiers are unregistered
  KVM: WARN if KVM attempts to do guest-related uaccess with "wrong"
    process
  KVM: WARN and reject guest-based uaccess if VM is dying
  KVM: Pre-check uaccesses in KVM's APIs to read/write guest memory
  KVM: VMX: Explicility free vmcs01, not the current VMCS, in vCPU free
    paths
  KVM: nVMX: Don't explicitly VMCLEAR+free() vmcs01's shadow VMCS when
    freeing vCPU
  KVM: nVMX: Cancel the nested VMX Preemption Timer's hrtimer in
    free_nested()
  KVM: Add lockdep-only APIs to query and assert that a vCPU is
    unreachable
  KVM: VMX: Explicitly remove dying vCPUs from the PI wakeup list
  KVM: nVMX: Don't switch to vmcs01 when freeing a vCPU
  KVM: nVMX: Don't load+put the vCPU when freeing nested state for a
    dying vCPU
  KVM: x86: Rename __x86_set_memory_region() =>
    x86_set_internal_memslot()

 arch/powerpc/include/asm/kvm_host.h |   1 -
 arch/powerpc/kvm/powerpc.c          |  11 +++
 arch/x86/kvm/lapic.c                |  42 ++++++-----
 arch/x86/kvm/vmx/nested.c           |  69 ++++++++---------
 arch/x86/kvm/vmx/posted_intr.c      |  68 ++++++++++-------
 arch/x86/kvm/vmx/posted_intr.h      |   1 +
 arch/x86/kvm/vmx/sgx.c              |   2 +-
 arch/x86/kvm/vmx/vmx.c              |  31 ++++----
 arch/x86/kvm/x86.c                  | 110 +++++++++++++++-------------
 arch/x86/kvm/x86.h                  |   4 +-
 include/linux/kvm_host.h            |  45 +++++++++++-
 virt/kvm/kvm_main.c                 |  94 +++++++++++++++---------
 12 files changed, 298 insertions(+), 180 deletions(-)


base-commit: 7e60162b16f9da0d2fa83da5c1723b6853a0ac1d
-- 
2.56.0.385.gac671c819a-goog


             reply	other threads:[~2026-10-30 21:21 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-30 21:20 Sean Christopherson [this message]
2026-10-30 21:20 ` [PATCH v4 01/23] KVM: Reject user accesses to guest memory if current->mm != kvm->mm Sean Christopherson
2026-10-30 21:20 ` [PATCH v4 02/23] KVM: nVMX: Don't force a full nested VM-Exit when destroying a vCPU Sean Christopherson
2026-10-30 21:20 ` [PATCH v4 03/23] KVM: PPC: Flush/zap all memslots on kvm_arch_flush_shadow_all() Sean Christopherson
2026-10-30 21:20 ` [PATCH v4 04/23] KVM: x86: Drop dead check on an existing memslot not having any pages Sean Christopherson
2026-10-30 21:20 ` [PATCH v4 05/23] KVM: WARN and error out if memslot update encounters existing slot with no pages Sean Christopherson
2026-10-30 21:20 ` [PATCH v4 06/23] KVM: x86: Unmap VMAs for KVM-internal memslots when the memslot is freed Sean Christopherson
2026-10-30 21:20 ` [PATCH v4 07/23] KVM: x86: Delete non-SMM internal memslot if creating SMM memslot fails Sean Christopherson
2026-10-30 21:20 ` [PATCH v4 08/23] KVM: x86: Process all address spaces when deleting internal memslot Sean Christopherson
2026-10-30 21:20 ` [PATCH v4 09/23] KVM: x86: Re-queue APICv update request if inhibiting APIC access page fails Sean Christopherson
2026-10-30 21:20 ` [PATCH v4 10/23] KVM: x86: Map a separate VMA for each address space for internal memslots Sean Christopherson
2026-10-30 22:54   ` sashiko-bot
2026-10-30 21:20 ` [PATCH v4 11/23] KVM: Disallow setting memslots when the VM is being destroyed Sean Christopherson
2026-10-30 21:21 ` [PATCH v4 12/23] KVM: Destroy memslots immediately after mmu_notifiers are unregistered Sean Christopherson
2026-10-30 23:16   ` sashiko-bot
2026-10-30 21:21 ` [PATCH v4 13/23] KVM: WARN if KVM attempts to do guest-related uaccess with "wrong" process Sean Christopherson
2026-10-30 21:21 ` [PATCH v4 14/23] KVM: WARN and reject guest-based uaccess if VM is dying Sean Christopherson
2026-10-30 21:21 ` [PATCH v4 15/23] KVM: Pre-check uaccesses in KVM's APIs to read/write guest memory Sean Christopherson
2026-10-30 21:21 ` [PATCH v4 16/23] KVM: VMX: Explicility free vmcs01, not the current VMCS, in vCPU free paths Sean Christopherson
2026-10-30 21:21 ` [PATCH v4 17/23] KVM: nVMX: Don't explicitly VMCLEAR+free() vmcs01's shadow VMCS when freeing vCPU Sean Christopherson
2026-10-30 21:21 ` [PATCH v4 18/23] KVM: nVMX: Cancel the nested VMX Preemption Timer's hrtimer in free_nested() Sean Christopherson
2026-10-30 21:21 ` [PATCH v4 19/23] KVM: Add lockdep-only APIs to query and assert that a vCPU is unreachable Sean Christopherson
2026-10-30 21:21 ` [PATCH v4 20/23] KVM: VMX: Explicitly remove dying vCPUs from the PI wakeup list Sean Christopherson
2026-10-30 21:21 ` [PATCH v4 21/23] KVM: nVMX: Don't switch to vmcs01 when freeing a vCPU Sean Christopherson
2026-10-30 21:21 ` [PATCH v4 22/23] KVM: nVMX: Don't load+put the vCPU when freeing nested state for a dying vCPU Sean Christopherson
2026-10-30 21:21 ` [PATCH v4 23/23] KVM: x86: Rename __x86_set_memory_region() => x86_set_internal_memslot() 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=20261030212112.2598640-1-seanjc@google.com \
    --to=seanjc@google.com \
    --cc=jmattson@google.com \
    --cc=jthoughton@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=maddy@linux.ibm.com \
    --cc=mason@kernel.org \
    --cc=npiggin@gmail.com \
    --cc=pbonzini@redhat.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