summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-15 08:12:47 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-15 08:12:47 -0700
commit9aa622dbaab8addcbe6f65f17c7b4d613d270f05 (patch)
treec83eec5d42516a43b6160e5f1c35c2053f49cb50
parent6a66840a68683d9361a9b31faf3bd8104428ad29 (diff)
parentc8f4cfe1cf93bce924e27f2abead7a4c4a487505 (diff)
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull kvm fixes from Paolo Bonzini: "Even more x86 fixes: - Avoid a false positive panic in the #PF handler, if the kernel triggers a page fault within the asynchronous page fault handler before the flags are reset. This can happen for example because of a perf NMI. - Always reset a vCPU's MMU pointer back to the root MMU when loading nested guest state fails during RSM or KVM_SET_NESTED_STATE. Otherwise KVM tries to run a non-nested guest with a nested MMU, which can result in a NULL pointer dereference attempting to get the nested MMU's pgd (EPTP or nested CR3)" * tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: KVM: nVMX: Reset MMU back to the root MMU if loading L2 state fails for !VM-Entry x86/kvm: Don't consume async #PF flags on a kernel #PF in NMI context
-rw-r--r--arch/x86/kernel/kvm.c32
-rw-r--r--arch/x86/kvm/vmx/nested.c4
2 files changed, 32 insertions, 4 deletions
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 6b0a5861ccb8..d8dd2cadcbf7 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -265,11 +265,39 @@ noinstr u32 kvm_read_and_reset_apf_flags(void)
}
EXPORT_SYMBOL_FOR_KVM(kvm_read_and_reset_apf_flags);
+static __always_inline bool kvm_apf_reason_pending(void)
+{
+ return __this_cpu_read(async_pf_enabled) &&
+ __this_cpu_read(apf_reason.flags);
+}
+
noinstr bool __kvm_handle_async_pf(struct pt_regs *regs, u32 token)
{
- u32 flags = kvm_read_and_reset_apf_flags();
irqentry_state_t state;
+ u32 flags;
+
+ if (!kvm_apf_reason_pending())
+ return false;
+
+ /*
+ * The guest does not enable KVM_ASYNC_PF_SEND_ALWAYS, so the host
+ * delivers async #PF only to user mode (or as a #PF VM-exit, which KVM
+ * reads itself). A #PF from kernel mode can still arrive between that
+ * delivery and the read of the reason flags, inside an NMI that
+ * interrupted it, for instance perf reading user memory for a call
+ * chain. Such a fault is not async, so leave the async PF flags
+ * untouched for the outer handler. Outside NMI context, on the other
+ * hand, async PF flags on a kernel-mode fault mean the host is broken.
+ */
+ if (!user_mode(regs)) {
+ if (likely(in_nmi()))
+ return false;
+ state = irqentry_enter(regs);
+ instrumentation_begin();
+ panic("Host injected async #PF in kernel mode\n");
+ }
+ flags = kvm_read_and_reset_apf_flags();
if (!flags)
return false;
@@ -285,8 +313,6 @@ noinstr bool __kvm_handle_async_pf(struct pt_regs *regs, u32 token)
panic("Host injected async #PF in interrupt disabled region\n");
if (flags & KVM_PV_REASON_PAGE_NOT_PRESENT) {
- if (unlikely(!(user_mode(regs))))
- panic("Host injected async #PF in kernel mode\n");
/* Page is swapped out by the host. */
kvm_async_pf_task_wait_schedule(token);
} else {
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index b25216862740..5165275128fc 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -3770,8 +3770,10 @@ vmentry_fail_vmexit_guest_mode:
vmentry_fail_vmexit:
vmx_switch_vmcs(vcpu, &vmx->vmcs01);
- if (!from_vmentry)
+ if (!from_vmentry) {
+ nested_ept_uninit_mmu_context(vcpu);
return NVMX_VMENTRY_VMEXIT;
+ }
nested_put_vmcs12_pages(vcpu);