From: Amirmohammad Eftekhar nested_check_guest_non_reg_state() only verifies that guest_activity_state is one of ACTIVE, HLT or WAIT_SIPI; it performs none of the activity-state cross-checks that VM entry requires. Per Intel's SDM, "Checks on Guest Non-Register State", when the valid bit of the VM-entry interruption-information field is set the interruption to be delivered "must not be one that would normally be blocked while a logical processor is in the activity state", and for the wait-for-SIPI state "No interruptions are allowed". The same section also requires that the activity state indicate the active state when the interruptibility-state field blocks by STI or MOV SS. KVM accepts a vmcs12 that violates both rules, and hardware does not catch the miss: prepare_vmcs02() never writes GUEST_ACTIVITY_STATE, so vmcs02 always carries active, and wait-for-SIPI is emulated in software only after a successful entry (the mp_state = INIT_RECEIVED arm). The injection, in contrast, is copied into vmcs02. The physical VMLAUNCH therefore sees {active, valid injection} -- a legal pair -- and succeeds. Because the offending field is stripped before hardware sees vmcs02, the missed-exit WARN in __nested_vmx_vmexit() can never fire for this class either. From L1's point of view a VMLAUNCH that bare metal rejects with a VM-entry failure (invalid guest state) instead succeeds, with L2 left parked in wait-for-SIPI holding a stale VM_ENTRY_INTR_INFO in vmcs02. Add the two activity-state cross-checks that KVM strips before hardware can enforce them. The HLT state additionally restricts which interruption types may be injected (external interrupt / NMI / #DB / #MC / pending-MTF only); that matrix is left for a follow-up as it needs the per-type table, whereas the two checks added here are unconditional and cover the fields KVM elides. Signed-off-by: Amirmohammad Eftekhar --- v2: No code changes. v1 (sent 2026-10-22, Message-ID ) was whitespace-damaged in transit by format=flowed in my mail client; resending cleanly via git send-email. arch/x86/kvm/vmx/nested.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 9b0bfa2f8..66c9d1ffe 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -3311,6 +3311,24 @@ static int nested_check_guest_non_reg_state(struct vmcs12 *vmcs12) vmcs12->guest_activity_state != GUEST_ACTIVITY_WAIT_SIPI)) return -EINVAL; + /* + * The activity state must be active if the interruptibility state + * blocks by STI or MOV SS. + */ + if (CC(vmcs12->guest_activity_state != GUEST_ACTIVITY_ACTIVE && + (vmcs12->guest_interruptibility_info & + (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)))) + return -EINVAL; + + /* + * An injected event must not be one that would be blocked in the + * guest's activity state; no interruptions are allowed in the + * wait-for-SIPI state. + */ + if (vmcs12->guest_activity_state == GUEST_ACTIVITY_WAIT_SIPI && + CC(vmcs12->vm_entry_intr_info_field & INTR_INFO_VALID_MASK)) + return -EINVAL; + return 0; } -- 2.54.0 (Apple Git-157)