Kernel KVM virtualization development
 help / color / mirror / Atom feed
* [PATCH 0/6] KVM: Harden kvm_vcpu_map() usage against memory leaks
@ 2026-07-24  0:47 Sean Christopherson
  2026-07-24  0:47 ` [PATCH 1/6] KVM: nVMX: Ensure KVM_REQ_GET_NESTED_STATE_PAGES is cleared on VM-Exit Sean Christopherson
                   ` (5 more replies)
  0 siblings, 6 replies; 11+ messages in thread
From: Sean Christopherson @ 2026-07-24  0:47 UTC (permalink / raw)
  To: Madhavan Srinivasan, Sean Christopherson, Paolo Bonzini
  Cc: Nicholas Piggin, linuxppc-dev, kvm, linux-kernel, Yosry Ahmed

Harden kvm_vcpu_map() usage against memory leaks by yelling if there's already
a valid mapping, and then unmapping the existing mapping before establishing a
new one.  To get there, add a CLASS() for local, on-stack usage, to guarantee
the map metadata is zero-initialized (well, so long as the CLASS() is used).

Prompted by 2f2312c422fd ("KVM: nVMX: Put vmcs12 pages if nested VM-Enter fails
due to invalid guest state").

Patch 1 is related in that it's needed to avoid tripping the new WARN.

The PPC change is compile-tested only.

Sean Christopherson (6):
  KVM: nVMX: Ensure KVM_REQ_GET_NESTED_STATE_PAGES is cleared on VM-Exit
  KVM: nSVM: Add CLASS()es for automagically handling local
    kvm_vcpu_map() usage
  KVM: nSVM: Use CLASS(kvm_vcpu_map_local) for SMM VMCB mappings
  KVM: nVMX: Use CLASS(kvm_vcpu_map_local_readonly) for MSR bitmap
    merging
  KVM: PPC: Use CLASS(kvm_vcpu_map_local_readonly) for patching dcbz
  KVM: Harden kvm_vcpu_map() against double-mapping and thus leaking
    references

 arch/powerpc/kvm/book3s_pr.c |  9 +++----
 arch/x86/kvm/svm/nested.c    | 18 ++++++--------
 arch/x86/kvm/svm/svm.c       | 46 +++++++++++++-----------------------
 arch/x86/kvm/vmx/nested.c    | 13 +++++-----
 include/linux/kvm_host.h     | 19 +++++++++++++++
 virt/kvm/kvm_main.c          |  3 +++
 6 files changed, 55 insertions(+), 53 deletions(-)


base-commit: 6bc96b971766fbbbbdd9fb2642cedacaf02da957
-- 
2.55.0.229.g6434b31f56-goog


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/6] KVM: nVMX: Ensure KVM_REQ_GET_NESTED_STATE_PAGES is cleared on VM-Exit
  2026-07-24  0:47 [PATCH 0/6] KVM: Harden kvm_vcpu_map() usage against memory leaks Sean Christopherson
@ 2026-07-24  0:47 ` Sean Christopherson
  2026-07-24  1:07   ` sashiko-bot
  2026-07-24  0:47 ` [PATCH 2/6] KVM: nSVM: Add CLASS()es for automagically handling local kvm_vcpu_map() usage Sean Christopherson
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 11+ messages in thread
From: Sean Christopherson @ 2026-07-24  0:47 UTC (permalink / raw)
  To: Madhavan Srinivasan, Sean Christopherson, Paolo Bonzini
  Cc: Nicholas Piggin, linuxppc-dev, kvm, linux-kernel, Yosry Ahmed

Always check and clear KVM_REQ_GET_NESTED_STATE_PAGES when emulating a
nested VM-Exit to ensure the request is cleared, even when KVM was built
with CONFIG_KVM_HYPERV=n, as KVM subtly relies on the "check" to clear
the flag and thus avoid double-mapping the vmcs12 pages, e.g. if KVM
manages to bail from VM-Enter without processing the request, and then
emulates VMLAUNCH or VMRESUME.

Fixes: b4f69df0f65e ("KVM: x86: Make Hyper-V emulation optional")
Cc: stable@vger.kernel.org
Reported-by: Yosry Ahmed <yosry@kernel.org>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/kvm/vmx/nested.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index b5460de4b1a7..f2518d67e7de 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -5066,8 +5066,9 @@ void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
 	/* trying to cancel vmlaunch/vmresume is a bug */
 	kvm_warn_on_nested_run_pending(vcpu);
 
-#ifdef CONFIG_KVM_HYPERV
+	/* Note, "checking" the request also clears the request. */
 	if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) {
+#ifdef CONFIG_KVM_HYPERV
 		/*
 		 * KVM_REQ_GET_NESTED_STATE_PAGES is also used to map
 		 * Enlightened VMCS after migration and we still need to
@@ -5075,8 +5076,8 @@ void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
 		 * the first L2 run.
 		 */
 		(void)nested_get_evmcs_page(vcpu);
-	}
 #endif
+	}
 
 	/* Service pending TLB flush requests for L2 before switching to L1. */
 	kvm_service_local_tlb_flush_requests(vcpu);
-- 
2.55.0.229.g6434b31f56-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/6] KVM: nSVM: Add CLASS()es for automagically handling local kvm_vcpu_map() usage
  2026-07-24  0:47 [PATCH 0/6] KVM: Harden kvm_vcpu_map() usage against memory leaks Sean Christopherson
  2026-07-24  0:47 ` [PATCH 1/6] KVM: nVMX: Ensure KVM_REQ_GET_NESTED_STATE_PAGES is cleared on VM-Exit Sean Christopherson
@ 2026-07-24  0:47 ` Sean Christopherson
  2026-07-24  0:47 ` [PATCH 3/6] KVM: nSVM: Use CLASS(kvm_vcpu_map_local) for SMM VMCB mappings Sean Christopherson
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Sean Christopherson @ 2026-07-24  0:47 UTC (permalink / raw)
  To: Madhavan Srinivasan, Sean Christopherson, Paolo Bonzini
  Cc: Nicholas Piggin, linuxppc-dev, kvm, linux-kernel, Yosry Ahmed

Add CLASS() definitions for locally mapping a PFN using kvm_vcpu_map()
given a vCPU+gfn pair.  In addition to eliminating the need to manually
do unmap(), e.g. in error paths, this will allow hardening KVM against
double-mapping without having to manually ensure every on-stack declaration
is zero-initialized.

Use "map local" as the primary terminology as the basic concept is more or
less the same as kmap_local(): ensure the current context has a kernel
mapping to the underlying memory.

Immediately convert the relatively straightforward nested SVM flows, and
defer converting the more involved SMM flows to a separate change.

No functional change intended.

Cc: Yosry Ahmed <yosry@kernel.org>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/kvm/svm/nested.c | 18 +++++++-----------
 arch/x86/kvm/svm/svm.c    |  8 +++-----
 include/linux/kvm_host.h  | 19 +++++++++++++++++++
 3 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index 5e3e280cd483..73f37b050d0a 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -1086,14 +1086,14 @@ int enter_svm_guest_mode(struct kvm_vcpu *vcpu, u64 vmcb12_gpa, bool from_vmrun)
 static int nested_svm_copy_vmcb12_to_cache(struct kvm_vcpu *vcpu, u64 vmcb12_gpa)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
-	struct kvm_host_map map;
 	struct vmcb *vmcb12;
 	int r = 0;
 
-	if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmcb12_gpa), &map))
+	CLASS(kvm_vcpu_map_local, m)(vcpu, gpa_to_gfn(vmcb12_gpa));
+	if (m.ret)
 		return -EFAULT;
 
-	vmcb12 = map.hva;
+	vmcb12 = m.map.hva;
 	nested_copy_vmcb_control_to_cache(svm, &vmcb12->control);
 	nested_copy_vmcb_save_to_cache(svm, &vmcb12->save);
 
@@ -1107,7 +1107,6 @@ static int nested_svm_copy_vmcb12_to_cache(struct kvm_vcpu *vcpu, u64 vmcb12_gpa
 		r = -EINVAL;
 	}
 
-	kvm_vcpu_unmap(vcpu, &map);
 	return r;
 }
 
@@ -1251,15 +1250,13 @@ static int nested_svm_vmexit_update_vmcb12(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 	struct vmcb *vmcb02 = svm->nested.vmcb02.ptr;
-	struct kvm_host_map map;
 	struct vmcb *vmcb12;
-	int rc;
 
-	rc = kvm_vcpu_map(vcpu, gpa_to_gfn(svm->nested.vmcb12_gpa), &map);
-	if (rc)
-		return rc;
+	CLASS(kvm_vcpu_map_local, m)(vcpu, gpa_to_gfn(svm->nested.vmcb12_gpa));
+	if (m.ret)
+		return m.ret;
 
-	vmcb12 = map.hva;
+	vmcb12 = m.map.hva;
 
 	vmcb12->save.es     = vmcb02->save.es;
 	vmcb12->save.cs     = vmcb02->save.cs;
@@ -1314,7 +1311,6 @@ static int nested_svm_vmexit_update_vmcb12(struct kvm_vcpu *vcpu)
 				       vmcb12->control.exit_int_info_err,
 				       KVM_ISA_SVM);
 
-	kvm_vcpu_unmap(vcpu, &map);
 	return 0;
 }
 
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 91286d46d13a..bf10483c0e8a 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -2216,7 +2216,6 @@ static int vmload_vmsave_interception(struct kvm_vcpu *vcpu, bool vmload)
 	u64 vmcb12_gpa = kvm_rax_read(vcpu);
 	struct vcpu_svm *svm = to_svm(vcpu);
 	struct vmcb *vmcb12;
-	struct kvm_host_map map;
 	int ret;
 
 	if (nested_svm_check_permissions(vcpu))
@@ -2227,10 +2226,11 @@ static int vmload_vmsave_interception(struct kvm_vcpu *vcpu, bool vmload)
 		return 1;
 	}
 
-	if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmcb12_gpa), &map))
+	CLASS(kvm_vcpu_map_local, m)(vcpu, gpa_to_gfn(vmcb12_gpa));
+	if (m.ret)
 		return kvm_handle_memory_failure(vcpu, X86EMUL_IO_NEEDED, NULL);
 
-	vmcb12 = map.hva;
+	vmcb12 = m.map.hva;
 
 	ret = kvm_skip_emulated_instruction(vcpu);
 
@@ -2243,8 +2243,6 @@ static int vmload_vmsave_interception(struct kvm_vcpu *vcpu, bool vmload)
 		svm_copy_vmloadsave_state(vmcb12, svm->vmcb01.ptr);
 	}
 
-	kvm_vcpu_unmap(vcpu, &map);
-
 	return ret;
 }
 
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 9db6eb4023c4..c54dbfdbc346 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1420,6 +1420,25 @@ static inline void kvm_vcpu_map_mark_dirty(struct kvm_vcpu *vcpu,
 		kvm_vcpu_mark_page_dirty(vcpu, map->gfn);
 }
 
+typedef struct {
+	struct kvm_vcpu *vcpu;
+	struct kvm_host_map map;
+	int ret;
+} kvm_vcpu_local_map_t;
+
+#define DEFINE_VCPU_MAP_CLASS(ro)					\
+DEFINE_CLASS(kvm_vcpu_map_local##ro, kvm_vcpu_local_map_t,		\
+	     if (!_T.ret) kvm_vcpu_unmap(_T.vcpu, &_T.map),		\
+	     ({								\
+		kvm_vcpu_local_map_t m = { .vcpu = vcpu };		\
+									\
+		m.ret = kvm_vcpu_map##ro(vcpu, gfn, &m.map);		\
+									\
+		m;							\
+	     }), struct kvm_vcpu *vcpu, gfn_t gfn);
+DEFINE_VCPU_MAP_CLASS();
+DEFINE_VCPU_MAP_CLASS(_readonly);
+
 unsigned long kvm_vcpu_gfn_to_hva(struct kvm_vcpu *vcpu, gfn_t gfn);
 unsigned long kvm_vcpu_gfn_to_hva_prot(struct kvm_vcpu *vcpu, gfn_t gfn, bool *writable);
 int kvm_vcpu_read_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, void *data, int offset,
-- 
2.55.0.229.g6434b31f56-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/6] KVM: nSVM: Use CLASS(kvm_vcpu_map_local) for SMM VMCB mappings
  2026-07-24  0:47 [PATCH 0/6] KVM: Harden kvm_vcpu_map() usage against memory leaks Sean Christopherson
  2026-07-24  0:47 ` [PATCH 1/6] KVM: nVMX: Ensure KVM_REQ_GET_NESTED_STATE_PAGES is cleared on VM-Exit Sean Christopherson
  2026-07-24  0:47 ` [PATCH 2/6] KVM: nSVM: Add CLASS()es for automagically handling local kvm_vcpu_map() usage Sean Christopherson
@ 2026-07-24  0:47 ` Sean Christopherson
  2026-07-24  0:47 ` [PATCH 4/6] KVM: nVMX: Use CLASS(kvm_vcpu_map_local_readonly) for MSR bitmap merging Sean Christopherson
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Sean Christopherson @ 2026-07-24  0:47 UTC (permalink / raw)
  To: Madhavan Srinivasan, Sean Christopherson, Paolo Bonzini
  Cc: Nicholas Piggin, linuxppc-dev, kvm, linux-kernel, Yosry Ahmed

Convert the kvm_vcpu_map() usage in the enter/leave SMM flows to the new
CLASS(kvm_vcpu_map_local) implementations, to eliminate the need to
manually do unmap() in error paths, and more importantly to eliminate more
of the open-coded on-stack "struct kvm_host_map" declarations.

No functional change intended.

Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/kvm/svm/svm.c | 38 ++++++++++++++------------------------
 1 file changed, 14 insertions(+), 24 deletions(-)

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index bf10483c0e8a..7a417e717fd9 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -4987,7 +4987,6 @@ static int svm_smi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
 static int svm_enter_smm(struct kvm_vcpu *vcpu, union kvm_smram *smram)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
-	struct kvm_host_map map_save;
 
 	if (!is_guest_mode(vcpu))
 		return 0;
@@ -5021,24 +5020,20 @@ static int svm_enter_smm(struct kvm_vcpu *vcpu, union kvm_smram *smram)
 	 * that, see svm_prepare_switch_to_guest()) which must be
 	 * preserved.
 	 */
-	if (kvm_vcpu_map(vcpu, gpa_to_gfn(svm->nested.hsave_msr), &map_save))
+	CLASS(kvm_vcpu_map_local, m_save)(vcpu, gpa_to_gfn(svm->nested.hsave_msr));
+	if (m_save.ret)
 		return 1;
 
 	BUILD_BUG_ON(offsetof(struct vmcb, save) != 0x400);
 
-	svm_copy_vmrun_state(map_save.hva + 0x400,
-			     &svm->vmcb01.ptr->save);
-
-	kvm_vcpu_unmap(vcpu, &map_save);
+	svm_copy_vmrun_state(m_save.map.hva + 0x400, &svm->vmcb01.ptr->save);
 	return 0;
 }
 
 static int svm_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
-	struct kvm_host_map map, map_save;
 	struct vmcb *vmcb12;
-	int ret;
 
 	const struct kvm_smram_state_64 *smram64 = &smram->smram64;
 
@@ -5055,22 +5050,23 @@ static int svm_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram)
 	if (!(smram64->efer & EFER_SVME))
 		return 1;
 
-	if (kvm_vcpu_map(vcpu, gpa_to_gfn(smram64->svm_guest_vmcb_gpa), &map))
+	CLASS(kvm_vcpu_map_local, m)(vcpu, gpa_to_gfn(smram64->svm_guest_vmcb_gpa));
+	if (m.ret)
 		return 1;
 
-	ret = 1;
-	if (kvm_vcpu_map(vcpu, gpa_to_gfn(svm->nested.hsave_msr), &map_save))
-		goto unmap_map;
+	CLASS(kvm_vcpu_map_local, m_save)(vcpu, gpa_to_gfn(svm->nested.hsave_msr));
+	if (m_save.ret)
+		return 1;
 
 	if (svm_allocate_nested(svm))
-		goto unmap_save;
+		return 1;
 
 	/*
 	 * Restore L1 host state from L1 HSAVE area as VMCB01 was
 	 * used during SMM (see svm_enter_smm())
 	 */
 
-	svm_copy_vmrun_state(&svm->vmcb01.ptr->save, map_save.hva + 0x400);
+	svm_copy_vmrun_state(&svm->vmcb01.ptr->save, m_save.map.hva + 0x400);
 
 	/*
 	 * Enter the nested guest now
@@ -5078,24 +5074,18 @@ static int svm_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram)
 
 	vmcb_mark_all_dirty(svm->vmcb01.ptr);
 
-	vmcb12 = map.hva;
+	vmcb12 = m.map.hva;
 	nested_copy_vmcb_control_to_cache(svm, &vmcb12->control);
 	nested_copy_vmcb_save_to_cache(svm, &vmcb12->save);
 
 	if (nested_svm_check_cached_vmcb12(vcpu) < 0)
-		goto unmap_save;
+		return 1;
 
 	if (enter_svm_guest_mode(vcpu, smram64->svm_guest_vmcb_gpa, false) != 0)
-		goto unmap_save;
+		return 1;
 
-	ret = 0;
 	vcpu->arch.nested_run_pending = KVM_NESTED_RUN_PENDING;
-
-unmap_save:
-	kvm_vcpu_unmap(vcpu, &map_save);
-unmap_map:
-	kvm_vcpu_unmap(vcpu, &map);
-	return ret;
+	return 0;
 }
 
 static void svm_enable_smi_window(struct kvm_vcpu *vcpu)
-- 
2.55.0.229.g6434b31f56-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/6] KVM: nVMX: Use CLASS(kvm_vcpu_map_local_readonly) for MSR bitmap merging
  2026-07-24  0:47 [PATCH 0/6] KVM: Harden kvm_vcpu_map() usage against memory leaks Sean Christopherson
                   ` (2 preceding siblings ...)
  2026-07-24  0:47 ` [PATCH 3/6] KVM: nSVM: Use CLASS(kvm_vcpu_map_local) for SMM VMCB mappings Sean Christopherson
@ 2026-07-24  0:47 ` Sean Christopherson
  2026-07-24  0:47 ` [PATCH 5/6] KVM: PPC: Use CLASS(kvm_vcpu_map_local_readonly) for patching dcbz Sean Christopherson
  2026-07-24  0:47 ` [PATCH 6/6] KVM: Harden kvm_vcpu_map() against double-mapping and thus leaking references Sean Christopherson
  5 siblings, 0 replies; 11+ messages in thread
From: Sean Christopherson @ 2026-07-24  0:47 UTC (permalink / raw)
  To: Madhavan Srinivasan, Sean Christopherson, Paolo Bonzini
  Cc: Nicholas Piggin, linuxppc-dev, kvm, linux-kernel, Yosry Ahmed

Convert the kvm_vcpu_map_readonly() usage in nVMX's MSR bitmap merging to
the new CLASS(kvm_vcpu_map_local_readonly) implementation, to eliminate the
last of the open-coded on-stack "struct kvm_host_map" declarations (in x86,
PPC still has one more to convert).

No functional change intended.

Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/kvm/vmx/nested.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index f2518d67e7de..ef79769c6287 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -730,7 +730,6 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
 	int msr;
 	unsigned long *msr_bitmap_l1;
 	unsigned long *msr_bitmap_l0 = vmx->nested.vmcs02.msr_bitmap;
-	struct kvm_host_map map;
 
 	/* Nothing to do if the MSR bitmap is not in use.  */
 	if (!cpu_has_vmx_msr_bitmap() ||
@@ -753,10 +752,11 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
 			return true;
 	}
 
-	if (kvm_vcpu_map_readonly(vcpu, gpa_to_gfn(vmcs12->msr_bitmap), &map))
+	CLASS(kvm_vcpu_map_local_readonly, m)(vcpu, gpa_to_gfn(vmcs12->msr_bitmap));
+	if (m.ret)
 		return false;
 
-	msr_bitmap_l1 = (unsigned long *)map.hva;
+	msr_bitmap_l1 = (unsigned long *)m.map.hva;
 
 	/*
 	 * To keep the control flow simple, pay eight 8-byte writes (sixteen
@@ -836,8 +836,6 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
 
 	nested_vmx_merge_pmu_msr_bitmaps(vcpu, msr_bitmap_l1, msr_bitmap_l0);
 
-	kvm_vcpu_unmap(vcpu, &map);
-
 	vmx->nested.force_msr_bitmap_recalc = false;
 
 	return true;
-- 
2.55.0.229.g6434b31f56-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 5/6] KVM: PPC: Use CLASS(kvm_vcpu_map_local_readonly) for patching dcbz
  2026-07-24  0:47 [PATCH 0/6] KVM: Harden kvm_vcpu_map() usage against memory leaks Sean Christopherson
                   ` (3 preceding siblings ...)
  2026-07-24  0:47 ` [PATCH 4/6] KVM: nVMX: Use CLASS(kvm_vcpu_map_local_readonly) for MSR bitmap merging Sean Christopherson
@ 2026-07-24  0:47 ` Sean Christopherson
  2026-07-24  1:03   ` sashiko-bot
  2026-07-24  0:47 ` [PATCH 6/6] KVM: Harden kvm_vcpu_map() against double-mapping and thus leaking references Sean Christopherson
  5 siblings, 1 reply; 11+ messages in thread
From: Sean Christopherson @ 2026-07-24  0:47 UTC (permalink / raw)
  To: Madhavan Srinivasan, Sean Christopherson, Paolo Bonzini
  Cc: Nicholas Piggin, linuxppc-dev, kvm, linux-kernel, Yosry Ahmed

Convert the kvm_vcpu_map() usage in PPC dcbz patching to the new
CLASS(kvm_vcpu_map_local) implementation, to eliminate the very last of the
the open-coded on-stack "struct kvm_host_map" declarations.  This will
allow adding hardening kvm_vcpu_map() against memory leaks (due to
clobbering the existing mapping).

No functional change intended.

Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/powerpc/kvm/book3s_pr.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index 2ba2dd26a7ea..da7a038e2700 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -639,27 +639,24 @@ static void kvmppc_set_pvr_pr(struct kvm_vcpu *vcpu, u32 pvr)
  */
 static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
 {
-	struct kvm_host_map map;
 	u64 hpage_offset;
 	u32 *page;
 	int i, r;
 
-	r = kvm_vcpu_map(vcpu, pte->raddr >> PAGE_SHIFT, &map);
-	if (r)
+	CLASS(kvm_vcpu_map_local, m)(vcpu, pte->raddr >> PAGE_SHIFT);
+	if (m.ret)
 		return;
 
 	hpage_offset = pte->raddr & ~PAGE_MASK;
 	hpage_offset &= ~0xFFFULL;
 	hpage_offset /= 4;
 
-	page = map.hva;
+	page = m.map.hva;
 
 	/* patch dcbz into reserved instruction, so we trap */
 	for (i=hpage_offset; i < hpage_offset + (HW_PAGE_SIZE / 4); i++)
 		if ((be32_to_cpu(page[i]) & 0xff0007ff) == INS_DCBZ)
 			page[i] &= cpu_to_be32(0xfffffff7);
-
-	kvm_vcpu_unmap(vcpu, &map);
 }
 
 static bool kvmppc_visible_gpa(struct kvm_vcpu *vcpu, gpa_t gpa)
-- 
2.55.0.229.g6434b31f56-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 6/6] KVM: Harden kvm_vcpu_map() against double-mapping and thus leaking references
  2026-07-24  0:47 [PATCH 0/6] KVM: Harden kvm_vcpu_map() usage against memory leaks Sean Christopherson
                   ` (4 preceding siblings ...)
  2026-07-24  0:47 ` [PATCH 5/6] KVM: PPC: Use CLASS(kvm_vcpu_map_local_readonly) for patching dcbz Sean Christopherson
@ 2026-07-24  0:47 ` Sean Christopherson
  2026-07-24  1:11   ` sashiko-bot
  5 siblings, 1 reply; 11+ messages in thread
From: Sean Christopherson @ 2026-07-24  0:47 UTC (permalink / raw)
  To: Madhavan Srinivasan, Sean Christopherson, Paolo Bonzini
  Cc: Nicholas Piggin, linuxppc-dev, kvm, linux-kernel, Yosry Ahmed

Now that all on-stack maps use CLASS(kvm_vcpu_map_local), i.e. now that all
maps are zero-allocated, explicitly put any existing mappings/references
when establishing a new mapping to harden against KVM bugs leaking memory,
but yell loudly as the owner of the map is still ultimately responsible for
the lifecycle of the mapping.

Suggested-by: Yosry Ahmed <yosry@kernel.org>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 virt/kvm/kvm_main.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 2df8ee9ecf6c..e9e32686e41b 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -3118,6 +3118,9 @@ int __kvm_vcpu_map(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map,
 		.pin = true,
 	};
 
+	if (WARN_ON_ONCE(map->hva))
+		kvm_vcpu_unmap(vcpu, map);
+
 	map->pinned_page = NULL;
 	map->page = NULL;
 	map->hva = NULL;
-- 
2.55.0.229.g6434b31f56-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 5/6] KVM: PPC: Use CLASS(kvm_vcpu_map_local_readonly) for patching dcbz
  2026-07-24  0:47 ` [PATCH 5/6] KVM: PPC: Use CLASS(kvm_vcpu_map_local_readonly) for patching dcbz Sean Christopherson
@ 2026-07-24  1:03   ` sashiko-bot
  2026-07-24  1:15     ` Sean Christopherson
  0 siblings, 1 reply; 11+ messages in thread
From: sashiko-bot @ 2026-07-24  1:03 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] The commit title claims to use `CLASS(kvm_vcpu_map_local_readonly)`, but the code uses the writable variant `CLASS(kvm_vcpu_map_local)`.
- [Low] The local variable `r` is declared but never used after the refactoring.
--

--- Patch [5]: [PATCH 5/6] KVM: PPC: Use CLASS(kvm_vcpu_map_local_readonly) for patching dcbz ---
commit 85b6110c0b5859c4a10a2a8a3cab84580d924a43
Author: Sean Christopherson <seanjc@google.com>

KVM: PPC: Use CLASS(kvm_vcpu_map_local_readonly) for patching dcbz

This commit converts the dcbz patching implementation in KVM PPC to use
the new scope-based CLASS(kvm_vcpu_map_local) infrastructure. It eliminates
the open-coded on-stack struct kvm_host_map to help harden the API against
memory leaks.

> KVM: PPC: Use CLASS(kvm_vcpu_map_local_readonly) for patching dcbz

[Severity: Medium]
The commit title mentions using CLASS(kvm_vcpu_map_local_readonly), but the
code below correctly uses the writable variant CLASS(kvm_vcpu_map_local)
since it needs to modify the memory. Should the title be updated to match
the implementation?

> diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
> --- a/arch/powerpc/kvm/book3s_pr.c
> +++ b/arch/powerpc/kvm/book3s_pr.c

[ ... ]

>  static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
>  {
> -	struct kvm_host_map map;
>  	u64 hpage_offset;
>  	u32 *page;
>  	int i, r;

[Severity: Low]
Does this leave the variable r unused in kvmppc_patch_dcbz()?

It looks like the original call to kvm_vcpu_map() was replaced, and nothing
else assigns or reads r. This might cause a compiler warning for configurations
that check for unused variables.

> 
> -	r = kvm_vcpu_map(vcpu, pte->raddr >> PAGE_SHIFT, &map);
> -	if (r)
> +	CLASS(kvm_vcpu_map_local, m)(vcpu, pte->raddr >> PAGE_SHIFT);
> +	if (m.ret)
>  		return;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260724004757.131420-1-seanjc@google.com?part=5

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/6] KVM: nVMX: Ensure KVM_REQ_GET_NESTED_STATE_PAGES is cleared on VM-Exit
  2026-07-24  0:47 ` [PATCH 1/6] KVM: nVMX: Ensure KVM_REQ_GET_NESTED_STATE_PAGES is cleared on VM-Exit Sean Christopherson
@ 2026-07-24  1:07   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-24  1:07 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] An L1 guest can trigger a silent host memory leak (pinned pages and kmap space) by repeatedly executing VMLAUNCH with an invalid guest state.
--

--- Patch [1]: [PATCH 1/6] KVM: nVMX: Ensure KVM_REQ_GET_NESTED_STATE_PAGES is cleared on VM-Exit ---
commit 529c03d57fc94827c8dfbb4372dfae1313c5dd93
Author: Sean Christopherson <seanjc@google.com>

KVM: nVMX: Ensure KVM_REQ_GET_NESTED_STATE_PAGES is cleared on VM-Exit

This patch ensures KVM_REQ_GET_NESTED_STATE_PAGES is always checked and 
cleared when emulating a nested VM-Exit. This prevents double-mapping 
vmcs12 pages if KVM manages to bail from VM-Enter without processing the 
request and then emulates VMLAUNCH or VMRESUME.

Cc: stable@vger.kernel.org

> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index b5460de4b1a72..f2518d67e7de5 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -5066,8 +5066,9 @@ void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
>  	/* trying to cancel vmlaunch/vmresume is a bug */
>  	kvm_warn_on_nested_run_pending(vcpu);
>  
> -#ifdef CONFIG_KVM_HYPERV
> +	/* Note, "checking" the request also clears the request. */
>  	if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) {
> +#ifdef CONFIG_KVM_HYPERV

[Severity: High]
This isn't a bug introduced by this patch, but I noticed a potential memory
leak related to how nested VM-Entry failures handle mapped pages.

If an L1 guest prepares a VMCS12 with valid addresses for mapped pages (like
virtual_apic_page_addr) but intentionally configures an invalid guest state 
(e.g., an invalid CR0 value), nested_vmx_enter_non_root_mode() maps the 
pages before validating the guest state:

arch/x86/kvm/vmx/nested.c:nested_vmx_enter_non_root_mode() {
    ...
    if (nested_vmx_check_guest_state(vcpu, vmcs12,
                                     &entry_failure_code)) {
        exit_reason.basic = EXIT_REASON_INVALID_STATE;
        vmcs12->exit_qualification = entry_failure_code;
        goto vmentry_fail_vmexit;
    }
    ...
}

The error path in vmentry_fail_vmexit synthesizes a VM-Exit back to L1 but 
returns without calling nested_put_vmcs12_pages() to unmap the resources:

arch/x86/kvm/vmx/nested.c:vmentry_fail_vmexit() {
    ...
    if (!from_vmentry)
        return NVMX_VMENTRY_VMEXIT;

    load_vmcs12_host_state(vcpu, vmcs12);
    vmcs12->vm_exit_reason = exit_reason.full;
    ...
    return NVMX_VMENTRY_VMEXIT;
}

If the L1 guest resumes and executes VMLAUNCH again, KVM calls
kvm_vcpu_map() on the already populated map structures:

virt/kvm/kvm_main.c:__kvm_vcpu_map() {
    ...
    map->pinned_page = NULL;
    map->page = NULL;
    map->hva = NULL;
    ...
}

This unconditionally clears the pointers without unmapping or verifying the
previous state, dropping the only KVM reference to the previously pinned
host page and kmap address.

Could a malicious L1 guest repeatedly trigger this in a tight loop to
exhaust host memory and kmap virtual space?

>  		/*
>  		 * KVM_REQ_GET_NESTED_STATE_PAGES is also used to map
>  		 * Enlightened VMCS after migration and we still need to

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260724004757.131420-1-seanjc@google.com?part=1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 6/6] KVM: Harden kvm_vcpu_map() against double-mapping and thus leaking references
  2026-07-24  0:47 ` [PATCH 6/6] KVM: Harden kvm_vcpu_map() against double-mapping and thus leaking references Sean Christopherson
@ 2026-07-24  1:11   ` sashiko-bot
  0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-24  1:11 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The newly added `WARN_ON_ONCE(map->hva)` in `__kvm_vcpu_map()` can be intentionally triggered by a malicious L1 guest during a failed nested VM-entry, leading to a host panic if `panic_on_warn` is set. This violates KVM subsystem guidelines against guest-reachable asserts.
--

--- Patch [6]: [PATCH 6/6] KVM: Harden kvm_vcpu_map() against double-mapping and thus leaking references ---
commit 8ccf1780ac5defdd7cc6ad600af4fce97f3731bd
Author: Sean Christopherson <seanjc@google.com>

KVM: Harden kvm_vcpu_map() against double-mapping and thus leaking references

This commit explicitly unmaps existing mappings in __kvm_vcpu_map() when
map->hva is already set. This change hardens the code against memory leaks 
from zero-allocated maps. It also adds a WARN_ON_ONCE() to alert on double 
mappings.

> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 2df8ee9ecf6c6..e9e32686e41be 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -3118,6 +3118,9 @@ int __kvm_vcpu_map(struct kvm_vcpu *vcpu, gfn_t gfn, struct kvm_host_map *map,
>  		.pin = true,
>  	};
>  
> +	if (WARN_ON_ONCE(map->hva))
> +		kvm_vcpu_unmap(vcpu, map);
> +

[Severity: High]
Can this WARN_ON_ONCE() be triggered by a malicious L1 guest, potentially
causing a host panic if panic_on_warn is set?

If an L1 guest sets up a VMCS12 that requires mapped pages (e.g. for APIC
accesses) but provides an invalid guest state, KVM maps the pages in
nested_vmx_enter_non_root_mode() via nested_get_vmcs12_pages(). If the state
check fails:

arch/x86/kvm/vmx/nested.c:nested_vmx_enter_non_root_mode() {
    ...
		if (nested_vmx_check_guest_state(vcpu, vmcs12,
						 &entry_failure_code)) {
			exit_reason.basic = EXIT_REASON_INVALID_STATE;
			vmcs12->exit_qualification = entry_failure_code;
			goto vmentry_fail_vmexit;
		}
    ...
}

KVM jumps to vmentry_fail_vmexit and returns to the L1 guest, but skips
calling nested_put_vmcs12_pages(). This leaves the pages mapped. When the L1
guest executes VMLAUNCH again, KVM attempts to map the pages again, map->hva
is already populated, and this WARN_ON_ONCE() is unconditionally triggered.

Does this violate the KVM subsystem guidelines against guest-reachable
assertions?

>  	map->pinned_page = NULL;
>  	map->page = NULL;
>  	map->hva = NULL;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260724004757.131420-1-seanjc@google.com?part=6

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 5/6] KVM: PPC: Use CLASS(kvm_vcpu_map_local_readonly) for patching dcbz
  2026-07-24  1:03   ` sashiko-bot
@ 2026-07-24  1:15     ` Sean Christopherson
  0 siblings, 0 replies; 11+ messages in thread
From: Sean Christopherson @ 2026-07-24  1:15 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: kvm

On Fri, Jul 24, 2026, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [Medium] The commit title claims to use
> `CLASS(kvm_vcpu_map_local_readonly)`, but the code uses the writable variant
> `CLASS(kvm_vcpu_map_local)`.

Gah, copy+paste fail.

> - [Low] The local variable `r` is declared but never used after the refactoring.

I'll fixup both of these when applying, assuming nothing else needs to be fixed
in the series.  Otherwise I'll address them in v2.

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-07-24  1:15 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-24  0:47 [PATCH 0/6] KVM: Harden kvm_vcpu_map() usage against memory leaks Sean Christopherson
2026-07-24  0:47 ` [PATCH 1/6] KVM: nVMX: Ensure KVM_REQ_GET_NESTED_STATE_PAGES is cleared on VM-Exit Sean Christopherson
2026-07-24  1:07   ` sashiko-bot
2026-07-24  0:47 ` [PATCH 2/6] KVM: nSVM: Add CLASS()es for automagically handling local kvm_vcpu_map() usage Sean Christopherson
2026-07-24  0:47 ` [PATCH 3/6] KVM: nSVM: Use CLASS(kvm_vcpu_map_local) for SMM VMCB mappings Sean Christopherson
2026-07-24  0:47 ` [PATCH 4/6] KVM: nVMX: Use CLASS(kvm_vcpu_map_local_readonly) for MSR bitmap merging Sean Christopherson
2026-07-24  0:47 ` [PATCH 5/6] KVM: PPC: Use CLASS(kvm_vcpu_map_local_readonly) for patching dcbz Sean Christopherson
2026-07-24  1:03   ` sashiko-bot
2026-07-24  1:15     ` Sean Christopherson
2026-07-24  0:47 ` [PATCH 6/6] KVM: Harden kvm_vcpu_map() against double-mapping and thus leaking references Sean Christopherson
2026-07-24  1:11   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox