Kernel KVM virtualization development
 help / color / mirror / Atom feed
* [PATCH] KVM: VMX: Load the EOI-exit bitmap into vmcs01, not the active VMCS
@ 2026-10-17  9:30 Amirmohammad Eftekhar
  2026-10-17  9:40 ` sashiko-bot
  0 siblings, 1 reply; 3+ messages in thread
From: Amirmohammad Eftekhar @ 2026-10-17  9:30 UTC (permalink / raw)
  To: seanjc, pbonzini; +Cc: kvm, linux-kernel

vmx_load_eoi_exitmap() writes EOI_EXIT_BITMAP0..3 directly with
vmcs_write64() and, unlike its siblings vmx_hwapic_isr_update() and
vmx_sync_pir_to_irr(),
does not take guard(vmx_vmcs01).  The EOI-exit bitmap belongs to L1's APIC,
but with nested virtual-interrupt-delivery an L2 can be active when KVM
refreshes it (e.g. via kvm_vcpu_reload_apic_access_page() /
vcpu_scan_ioapic()), so the writes land in vmcs02 instead of vmcs01: L2's
EOI-exit bitmap is corrupted and vmcs01's is left stale until the next L1
refresh.

Add guard(vmx_vmcs01), matching the sibling APICv callbacks.

Signed-off-by: Amirmohammad Eftekhar <amirmohammad.eftekhar@cispa.de>
---
 arch/x86/kvm/vmx/vmx.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index b341af4c6..1f802cdbe 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -7082,6 +7082,13 @@ void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
 	if (!kvm_vcpu_apicv_active(vcpu))
 		return;
 
+	/*
+	 * The EOI-exit bitmap tracks L1's APIC, so it must land in vmcs01, not
+	 * whichever VMCS is currently loaded; a nested VID L2 can be active
+	 * here.  Mirror vmx_hwapic_isr_update()/vmx_sync_pir_to_irr().
+	 */
+	guard(vmx_vmcs01)(vcpu);
+
 	vmcs_write64(EOI_EXIT_BITMAP0, eoi_exit_bitmap[0]);
 	vmcs_write64(EOI_EXIT_BITMAP1, eoi_exit_bitmap[1]);
 	vmcs_write64(EOI_EXIT_BITMAP2, eoi_exit_bitmap[2]);
-- 
2.54.0 (Apple Git-157)


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

* Re: [PATCH] KVM: VMX: Load the EOI-exit bitmap into vmcs01, not the active VMCS
  2026-10-17  9:30 [PATCH] KVM: VMX: Load the EOI-exit bitmap into vmcs01, not the active VMCS Amirmohammad Eftekhar
@ 2026-10-17  9:40 ` sashiko-bot
  2026-10-17 14:46   ` Sean Christopherson
  0 siblings, 1 reply; 3+ messages in thread
From: sashiko-bot @ 2026-10-17  9:40 UTC (permalink / raw)
  To: Amirmohammad Eftekhar; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] KVM: VMX: vmx_load_eoi_exitmap() comment mismatch and deferred L2 update
--

commit b2b472dc800418ff9ed851c85722ed6e99a11a91
Author: Amirmohammad Eftekhar <amirmohammad.eftekhar@cispa.de>

KVM: VMX: Load the EOI-exit bitmap into vmcs01, not the active VMCS

This commit adds guard(vmx_vmcs01) to vmx_load_eoi_exitmap() so that updates
to EOI_EXIT_BITMAP0..3 target vmcs01 rather than whichever VMCS happens to be
loaded on the CPU.

>     KVM: VMX: Load the EOI-exit bitmap into vmcs01, not the active VMCS
>     
>     vmx_load_eoi_exitmap() writes EOI_EXIT_BITMAP0..3 directly with
>     vmcs_write64() and, unlike its siblings vmx_hwapic_isr_update() and
>     vmx_sync_pir_to_irr(),
>     does not take guard(vmx_vmcs01).  The EOI-exit bitmap belongs to L1's APIC,
>     but with nested virtual-interrupt-delivery an L2 can be active when KVM
>     refreshes it (e.g. via kvm_vcpu_reload_apic_access_page() /
>     vcpu_scan_ioapic()), so the writes land in vmcs02 instead of vmcs01: L2's
>     EOI-exit bitmap is corrupted and vmcs01's is left stale until the next L1
>     refresh.
>     
>     Add guard(vmx_vmcs01), matching the sibling APICv callbacks.
>     
>     Signed-off-by: Amirmohammad Eftekhar <amirmohammad.eftekhar@cispa.de>

> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index 612ab07d4100f..ec2ea3e1d14d8 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -7139,6 +7139,13 @@ void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
>  	if (!kvm_vcpu_apicv_active(vcpu))
>  		return;
>  
> +	/*
> +	 * The EOI-exit bitmap tracks L1's APIC, so it must land in vmcs01, not
> +	 * whichever VMCS is currently loaded; a nested VID L2 can be active
> +	 * here.  Mirror vmx_hwapic_isr_update()/vmx_sync_pir_to_irr().
> +	 */
> +	guard(vmx_vmcs01)(vcpu);
> +
>  	vmcs_write64(EOI_EXIT_BITMAP0, eoi_exit_bitmap[0]);
>  	vmcs_write64(EOI_EXIT_BITMAP1, eoi_exit_bitmap[1]);
>  	vmcs_write64(EOI_EXIT_BITMAP2, eoi_exit_bitmap[2]);

[Severity: Medium]
Can vcpu_scan_ioapic() or kvm_vcpu_reload_apic_access_page() actually trigger
vmx_load_eoi_exitmap() while L2 is active, as described in the commit message
and comment?

Looking at arch/x86/kvm/x86.c, kvm_vcpu_reload_apic_access_page() only calls
set_apic_access_page_addr:

static void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu)
{
	if (!lapic_in_kernel(vcpu))
		return;

	kvm_x86_call(set_apic_access_page_addr)(vcpu);
}

Meanwhile, vcpu_scan_ioapic() in arch/x86/kvm/x86.c explicitly defers
KVM_REQ_LOAD_EOI_EXITMAP when the vCPU is in guest mode:

	if (is_guest_mode(vcpu))
		vcpu->arch.load_eoi_exitmap_pending = true;
	else
		kvm_make_request(KVM_REQ_LOAD_EOI_EXITMAP, vcpu);

And leave_guest_mode() in arch/x86/kvm/regs.h only raises
KVM_REQ_LOAD_EOI_EXITMAP when leaving L2:

	if (vcpu->arch.load_eoi_exitmap_pending) {
		vcpu->arch.load_eoi_exitmap_pending = false;
		kvm_make_request(KVM_REQ_LOAD_EOI_EXITMAP, vcpu);
	}

With load_eoi_exitmap_pending still in place, vcpu_scan_ioapic() will not
invoke vmx_load_eoi_exitmap() while L2 is active (it seems
vmx_load_eoi_exitmap() is only reached with is_guest_mode(vcpu) true if
leave_guest_mode() raises KVM_REQ_LOAD_EOI_EXITMAP and guest mode is
re-entered before vcpu_enter_guest() processes requests, such as via
vmx_set_nested_state()). Now that vmx_load_eoi_exitmap() uses
guard(vmx_vmcs01), should the load_eoi_exitmap_pending deferral in
vcpu_scan_ioapic() and leave_guest_mode() be removed so that
KVM_REQ_LOAD_EOI_EXITMAP is raised immediately while L2 is active, or should
the commit message and comment be updated to reflect the actual call path?

Also, both the commit message and the new comment state that this mirrors
vmx_sync_pir_to_irr() taking guard(vmx_vmcs01), but vmx_sync_pir_to_irr() in
arch/x86/kvm/vmx/vmx.c checks !is_guest_mode(vcpu) instead of using
guard(vmx_vmcs01):

	if (!is_guest_mode(vcpu) && kvm_vcpu_apicv_active(vcpu))
		vmx_set_rvi(max_irr);
	else if (max_irr_is_from_pir)
		kvm_make_request(KVM_REQ_EVENT, vcpu);

Should the reference to vmx_sync_pir_to_irr() in the comment and commit
message be adjusted as well?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261017093016.32348-2-amirmohammad.eftekhar@cispa.de?part=1

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

* Re: [PATCH] KVM: VMX: Load the EOI-exit bitmap into vmcs01, not the active VMCS
  2026-10-17  9:40 ` sashiko-bot
@ 2026-10-17 14:46   ` Sean Christopherson
  0 siblings, 0 replies; 3+ messages in thread
From: Sean Christopherson @ 2026-10-17 14:46 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Amirmohammad Eftekhar, kvm

On Sat, Oct 17, 2026, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] KVM: VMX: vmx_load_eoi_exitmap() comment mismatch and deferred L2 update
> --
> 
> commit b2b472dc800418ff9ed851c85722ed6e99a11a91
> Author: Amirmohammad Eftekhar <amirmohammad.eftekhar@cispa.de>
> 
> KVM: VMX: Load the EOI-exit bitmap into vmcs01, not the active VMCS
> 
> This commit adds guard(vmx_vmcs01) to vmx_load_eoi_exitmap() so that updates
> to EOI_EXIT_BITMAP0..3 target vmcs01 rather than whichever VMCS happens to be
> loaded on the CPU.
> 
> >     KVM: VMX: Load the EOI-exit bitmap into vmcs01, not the active VMCS
> >     
> >     vmx_load_eoi_exitmap() writes EOI_EXIT_BITMAP0..3 directly with
> >     vmcs_write64() and, unlike its siblings vmx_hwapic_isr_update() and
> >     vmx_sync_pir_to_irr(),
> >     does not take guard(vmx_vmcs01).  The EOI-exit bitmap belongs to L1's APIC,
> >     but with nested virtual-interrupt-delivery an L2 can be active when KVM
> >     refreshes it (e.g. via kvm_vcpu_reload_apic_access_page() /
> >     vcpu_scan_ioapic()), so the writes land in vmcs02 instead of vmcs01: L2's
> >     EOI-exit bitmap is corrupted and vmcs01's is left stale until the next L1
> >     refresh.
> >     
> >     Add guard(vmx_vmcs01), matching the sibling APICv callbacks.
> >     
> >     Signed-off-by: Amirmohammad Eftekhar <amirmohammad.eftekhar@cispa.de>
> 
> > diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> > index 612ab07d4100f..ec2ea3e1d14d8 100644
> > --- a/arch/x86/kvm/vmx/vmx.c
> > +++ b/arch/x86/kvm/vmx/vmx.c
> > @@ -7139,6 +7139,13 @@ void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
> >  	if (!kvm_vcpu_apicv_active(vcpu))
> >  		return;
> >  
> > +	/*
> > +	 * The EOI-exit bitmap tracks L1's APIC, so it must land in vmcs01, not
> > +	 * whichever VMCS is currently loaded; a nested VID L2 can be active
> > +	 * here.  Mirror vmx_hwapic_isr_update()/vmx_sync_pir_to_irr().
> > +	 */
> > +	guard(vmx_vmcs01)(vcpu);
> > +
> >  	vmcs_write64(EOI_EXIT_BITMAP0, eoi_exit_bitmap[0]);
> >  	vmcs_write64(EOI_EXIT_BITMAP1, eoi_exit_bitmap[1]);
> >  	vmcs_write64(EOI_EXIT_BITMAP2, eoi_exit_bitmap[2]);
> 
> [Severity: Medium]
> Can vcpu_scan_ioapic() or kvm_vcpu_reload_apic_access_page() actually trigger
> vmx_load_eoi_exitmap() while L2 is active, as described in the commit message
> and comment?

Not in normal operation, no.  Maybe if userspace does something bizarre and forces
the vCPU back into L2 after the exit, but before KVM_RUN?  Regardless, we should
rip out the deferred update, I simply missed it when removing all the others,
probably because it was buring in kvm_vcpu_arch instead of vcpu_vmx.

Not yet tested...

---
From: Sean Christopherson <seanjc@google.com>
Date: Sat, 17 Oct 2026 07:33:11 -0700
Subject: [PATCH] KVM: x86: Switch to vmcs01 to update EOIT exiting bitmap
 on-demand if L2 is active

If KVM needs to update the EOI bitmap while L2 is running, temporarily load
vmcs01 and immediately refresh the bitmap in vmcs01 instead of deferring
the update until the next nested VM-Exit.  I.e. give the EOI bitmap the
same treatment as the many other updates that were previously deferred.

Reported-by: Amirmohammad Eftekhar <amirmohammad.eftekhar@cispa.de>
Closes: https://lore.kernel.org/all/20261017093016.32348-2-amirmohammad.eftekhar@cispa.de
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/include/asm/kvm_host.h |  2 +-
 arch/x86/kvm/regs.h             |  6 ------
 arch/x86/kvm/vmx/vmx.c          |  2 ++
 arch/x86/kvm/x86.c              | 13 -------------
 4 files changed, 3 insertions(+), 20 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index e2eef7057bd3..9583bde5c848 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -108,7 +108,7 @@
 #define KVM_REQ_HV_RESET		KVM_ARCH_REQ(20)
 #define KVM_REQ_HV_EXIT			KVM_ARCH_REQ(21)
 #define KVM_REQ_HV_STIMER		KVM_ARCH_REQ(22)
-#define KVM_REQ_LOAD_EOI_EXITMAP	KVM_ARCH_REQ(23)
+/*#define FREE!!!  USE ME!!!		KVM_ARCH_REQ(23) */
 #define KVM_REQ_GET_NESTED_STATE_PAGES	KVM_ARCH_REQ(24)
 #define KVM_REQ_APICV_UPDATE \
 	KVM_ARCH_REQ_FLAGS(25, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
diff --git a/arch/x86/kvm/regs.h b/arch/x86/kvm/regs.h
index 97c17b120a57..04d047f46753 100644
--- a/arch/x86/kvm/regs.h
+++ b/arch/x86/kvm/regs.h
@@ -463,12 +463,6 @@ static inline void enter_guest_mode(struct kvm_vcpu *vcpu)
 static inline void leave_guest_mode(struct kvm_vcpu *vcpu)
 {
 	vcpu->arch.hflags &= ~HF_GUEST_MASK;
-
-	if (vcpu->arch.load_eoi_exitmap_pending) {
-		vcpu->arch.load_eoi_exitmap_pending = false;
-		kvm_make_request(KVM_REQ_LOAD_EOI_EXITMAP, vcpu);
-	}
-
 	vcpu->stat.guest_mode = 0;
 }
 
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index b341af4c6057..59b48d959ee0 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -7082,6 +7082,8 @@ void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
 	if (!kvm_vcpu_apicv_active(vcpu))
 		return;
 
+	guard(vmx_vmcs01)(vcpu);
+
 	vmcs_write64(EOI_EXIT_BITMAP0, eoi_exit_bitmap[0]);
 	vmcs_write64(EOI_EXIT_BITMAP1, eoi_exit_bitmap[1]);
 	vmcs_write64(EOI_EXIT_BITMAP2, eoi_exit_bitmap[2]);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 32563a91fba9..0028d57e964a 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8062,17 +8062,6 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
 		kvm_ioapic_scan_entry(vcpu, vcpu->arch.ioapic_handled_vectors);
 #endif
 
-	if (is_guest_mode(vcpu))
-		vcpu->arch.load_eoi_exitmap_pending = true;
-	else
-		kvm_make_request(KVM_REQ_LOAD_EOI_EXITMAP, vcpu);
-}
-
-static void vcpu_load_eoi_exitmap(struct kvm_vcpu *vcpu)
-{
-	if (!kvm_apic_hw_enabled(vcpu->arch.apic))
-		return;
-
 #ifdef CONFIG_KVM_HYPERV
 	if (to_hv_vcpu(vcpu)) {
 		u64 eoi_exit_bitmap[4];
@@ -8240,8 +8229,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 		}
 		if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu))
 			vcpu_scan_ioapic(vcpu);
-		if (kvm_check_request(KVM_REQ_LOAD_EOI_EXITMAP, vcpu))
-			vcpu_load_eoi_exitmap(vcpu);
 		if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
 			kvm_vcpu_reload_apic_access_page(vcpu);
 #ifdef CONFIG_KVM_HYPERV

base-commit: dea4f6380f4ec96e8f3b0aaf2343764bd0d25ef4
-- 

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

end of thread, other threads:[~2026-10-17 14:46 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-17  9:30 [PATCH] KVM: VMX: Load the EOI-exit bitmap into vmcs01, not the active VMCS Amirmohammad Eftekhar
2026-10-17  9:40 ` sashiko-bot
2026-10-17 14:46   ` Sean Christopherson

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