* [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* 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
* [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* 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 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
* [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 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