From: Sean Christopherson <seanjc@google.com>
To: Hyunwoo Kim <imv4bel@gmail.com>
Cc: pbonzini@redhat.com, tglx@kernel.org, mingo@redhat.com,
bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org,
dwmw2@infradead.org, kvm@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH] KVM: nVMX: Don't load L1's host state when freeing a vCPU
Date: Mon, 3 Aug 2026 17:44:22 -0700 [thread overview]
Message-ID: <anE15pfdYLCZtHCn@google.com> (raw)
In-Reply-To: <am3Bs0DjZ5kay9NJ@v4bel>
On Sat, Aug 01, 2026, Hyunwoo Kim wrote:
> Don't load L1's host state when kicking a vCPU out of nested guest mode as
> part of freeing the vCPU, as loading host state processes vmcs12's VM-Exit
> MSR load list, i.e. reads an (index, value) pair out of guest memory and
> feeds it to kvm_emulate_msr_write() with host_initiated=false. Letting the
> guest emulate WRMSR against VM-scope state that KVM is actively tearing
> down goes sideways in at least two ways.
>
> Writing HV_X64_MSR_ICR sends an IPI, which for a non-shorthand,
> non-broadcast destination walks kvm->arch.apic_map to dereference the
> target's local APIC. kvm_free_lapic() neither rebuilds nor dirties the map,
> and the map is freed only after all vCPUs are destroyed, i.e. the map still
> points at the already-freed local APIC of a previously destroyed vCPU. This
> requires userspace to expose Hyper-V's CPUID to the guest. Writing
> MSR_KVM_SYSTEM_TIME_NEW activates the kvmclock gfn=>pfn cache, which leaves
> the cache's list entry, resident in the about-to-be-freed vCPU, linked into
> kvm->gpc_list; the next vCPU to manipulate the list writes through that
> entry.
Wouldn't this also require an "unclean" shutdown of the VM, because the VM would
still need live memslots in order to process the MSR load/store lists. I wonder
if that's an avenue to a short-term stopgap "fix" as well as long-term hardening.
E.g. if KVM were to nuke memslots as part of kvm_destroy_vm(), I think that would
plug this particular hole?
> The vCPU will never run again, so nothing can observe the loaded host
> state. Simply restore KVM's MMU pointers so that they aren't left pointing
> at the nested MMU, and bail. nSVM does the same, i.e. doesn't emulate a
> VM-Exit when forcibly leaving nested mode, and performs only the equivalent
> MMU cleanup.
I don't have the links off-hand, but nSVM's behavior of not emulating VM-Exit
has also led to problems (I think we've failed to account for things that are
handled by the VM-Exit path, on multiple occassions). That said, emulating a
VM-Exit while a vCPU is being destroyed is beyond awful, e.g. it requires
loading+putting the vCPU, which is its own gigantic can of worms.
> Bail just before the branch that splits the success and VM-Fail paths, as
> leaving guest mode, canceling the VMX-preemption timer, and switching back
> to vmcs01 are all needed by the free path. Canceling the timer is in fact
> the only reason the free path goes through an emulated VM-Exit, see commit
> b4b65b5642d6 ("KVM: x86: cleanup freeing of nested state").
IIRC, we've accumulated more horrors since then. I completely agree this code
is buggy and needs to be fixed, but I don't want to take a quick-and-dirty fix,
at least not without an exit strategy, which would/should force us to assess
exactly what is/isn't needed from the __nested_vmx_vmexit() flow.
> Fixes: b4b65b5642d6 ("KVM: x86: cleanup freeing of nested state")
> Cc: stable@vger.kernel.org
> Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
> ---
> arch/x86/kvm/vmx/nested.c | 12 ++++++++++++
> arch/x86/kvm/vmx/vmx.h | 3 +++
> 2 files changed, 15 insertions(+)
>
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index ddf6df7bee93b2..8d58547acb1887 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -384,6 +384,8 @@ static void free_nested(struct kvm_vcpu *vcpu)
> */
> void nested_vmx_free_vcpu(struct kvm_vcpu *vcpu)
> {
> + to_vmx(vcpu)->nested.vcpu_is_dying = true;
> +
> vcpu_load(vcpu);
> vmx_leave_nested(vcpu);
> vcpu_put(vcpu);
> @@ -5173,6 +5175,16 @@ void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
> /* in case we halted in L2 */
> kvm_set_mp_state(vcpu, KVM_MP_STATE_RUNNABLE);
>
> + /*
> + * Don't emulate guest-controlled state, e.g. vmcs12's VM-Exit MSR load
> + * list, when freeing the vCPU. Bail only after leaving guest mode,
> + * canceling the preemption timer, and switching back to vmcs01.
> + */
> + if (vmx->nested.vcpu_is_dying) {
> + nested_ept_uninit_mmu_context(vcpu);
> + return;
> + }
> +
> if (likely(!vmx->fail)) {
> if (vm_exit_reason != -1)
> trace_kvm_nested_vmexit_inject(vmcs12->vm_exit_reason,
> diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
> index dc8517f15bc463..2bacd3fe4c7ded 100644
> --- a/arch/x86/kvm/vmx/vmx.h
> +++ b/arch/x86/kvm/vmx/vmx.h
> @@ -76,6 +76,9 @@ struct nested_vmx {
> gpa_t vmxon_ptr;
> bool pml_full;
>
> + /* Set when freeing the vCPU, to suppress emulation of guest state. */
> + bool vcpu_is_dying;
> +
> /* The guest-physical address of the current VMCS L1 keeps for L2 */
> gpa_t current_vmptr;
> /*
> --
> 2.43.0
>
prev parent reply other threads:[~2026-08-04 0:44 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-01 9:51 [PATCH] KVM: nVMX: Don't load L1's host state when freeing a vCPU Hyunwoo Kim
2026-08-04 0:44 ` Sean Christopherson [this message]
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=anE15pfdYLCZtHCn@google.com \
--to=seanjc@google.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=dwmw2@infradead.org \
--cc=imv4bel@gmail.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=pbonzini@redhat.com \
--cc=tglx@kernel.org \
--cc=x86@kernel.org \
/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