mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] KVM: nVMX: Reject nested VM-entry in wait-for-SIPI with a pending event injection
@ 2026-10-22 21:12 Amirmohammad Eftekhar
  2026-10-22 21:42 ` Sean Christopherson
  0 siblings, 1 reply; 5+ messages in thread
From: Amirmohammad Eftekhar @ 2026-10-22 21:12 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini
  Cc: kvm, linux-kernel, 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 <amirmohammad.eftekhar@cispa.de>
---
  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)

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

* Re: [PATCH] KVM: nVMX: Reject nested VM-entry in wait-for-SIPI with a pending event injection
  2026-10-22 21:12 [PATCH] KVM: nVMX: Reject nested VM-entry in wait-for-SIPI with a pending event injection Amirmohammad Eftekhar
@ 2026-10-22 21:42 ` Sean Christopherson
  2026-10-22 21:51   ` [PATCH v3 0/2] KVM: nVMX: Add the activity-state cross-checks VM-entry requires amirmohammad.eftekhar
                     ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Sean Christopherson @ 2026-10-22 21:42 UTC (permalink / raw)
  To: Amirmohammad Eftekhar
  Cc: Paolo Bonzini, kvm, linux-kernel, Amirmohammad Eftekhar

On Thu, Oct 22, 2026, Amirmohammad Eftekhar wrote:
> 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. 

Please split this into two patches, one for each consistency check.  The justification
for why KVM needs these checks is the same, but the changes themselves are
independent.

> 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 <amirmohammad.eftekhar@cispa.de>
> ---
>  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.
> +	 */

Eh, drop this comment, it's pretty much just restating the code verbatim.

> +	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.
> +	 */

I think a TODO would be helpful.  Actually, what if we structure the entire
function as a switch-statement?  Gah, never mind, the check on MOV-SS and STI
blocking makes that annoying to deal with.

Anyways, how about this?

	/* 
	 * Injected events are disallowed if they are blocked by the activity
	 * state.  All injectable events are allowed in the active state, all
	 * are blocked by Wait-For-SIPI, and a small subset are allowed for HLT.
	 *
	 * TODO: Add consistency checks for HLT with an injected event.
	 */
	if (CC(vmcs12->guest_activity_state == GUEST_ACTIVITY_WAIT_SIPI &&
	       vmcs12->vm_entry_intr_info_field & INTR_INFO_VALID_MASK))
		return -EINVAL;


> +	if (vmcs12->guest_activity_state == GUEST_ACTIVITY_WAIT_SIPI &&
> +	    CC(vmcs12->vm_entry_intr_info_field & INTR_INFO_VALID_MASK))

Put the whole if-statement in the CC(), otherwise the error that shows up in the
trace will just be "vmcs12->vm_entry_intr_info_field & INTR_INFO_VALID_MASK"
without any context.

> +		return -EINVAL;
> +
>  	return 0;
>  }
>  -- 2.54.0 (Apple Git-157)
> 

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

* [PATCH v3 0/2] KVM: nVMX: Add the activity-state cross-checks VM-entry requires
  2026-10-22 21:42 ` Sean Christopherson
@ 2026-10-22 21:51   ` amirmohammad.eftekhar
  2026-10-22 21:51   ` [PATCH v3 1/2] KVM: nVMX: Reject nested VM-entry in a non-active state blocked by STI/MOV-SS amirmohammad.eftekhar
  2026-10-22 21:51   ` [PATCH v3 2/2] KVM: nVMX: Reject nested VM-entry in wait-for-SIPI with a pending event injection amirmohammad.eftekhar
  2 siblings, 0 replies; 5+ messages in thread
From: amirmohammad.eftekhar @ 2026-10-22 21:51 UTC (permalink / raw)
  To: seanjc, pbonzini
  Cc: kvm, linux-kernel, amirmohammadeftekhar, Amirmohammad Eftekhar

From: Amirmohammad Eftekhar <amirmohammad.eftekhar@cispa.de>

nested_check_guest_non_reg_state() only verifies that guest_activity_state is
one of ACTIVE/HLT/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":
the activity state must indicate the active state when the interruptibility-state
field blocks by STI or MOV SS, and when the valid bit of the VM-entry
interruption-information field is set the interruption "must not be one that
would normally be blocked" in the activity state -- for wait-for-SIPI, "No
interruptions are allowed".

KVM cannot rely on hardware to catch either miss: prepare_vmcs02() never writes
GUEST_ACTIVITY_STATE, so vmcs02 always carries the active state while the
injection is copied into vmcs02, and the physical VMLAUNCH sees a legal pair and
succeeds.  The missed-exit WARN in __nested_vmx_vmexit() cannot fire for this
class either, since the offending field is stripped before hardware sees vmcs02.

The two checks share this justification but are independent changes, so they are
split into separate patches per review feedback.

v3:
  - split into two patches, one per consistency check (Sean)
  - drop the comment that merely restated the code (Sean)
v2: clean resend of v1 (v1 was whitespace-damaged in transit by a mail client).

Amirmohammad Eftekhar (2):
  KVM: nVMX: Reject nested VM-entry in a non-active state blocked by
    STI/MOV-SS
  KVM: nVMX: Reject nested VM-entry in wait-for-SIPI with a pending
    event injection

 arch/x86/kvm/vmx/nested.c | 9 +++++++++
 1 file changed, 9 insertions(+)

-- 
2.34.1


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

* [PATCH v3 1/2] KVM: nVMX: Reject nested VM-entry in a non-active state blocked by STI/MOV-SS
  2026-10-22 21:42 ` Sean Christopherson
  2026-10-22 21:51   ` [PATCH v3 0/2] KVM: nVMX: Add the activity-state cross-checks VM-entry requires amirmohammad.eftekhar
@ 2026-10-22 21:51   ` amirmohammad.eftekhar
  2026-10-22 21:51   ` [PATCH v3 2/2] KVM: nVMX: Reject nested VM-entry in wait-for-SIPI with a pending event injection amirmohammad.eftekhar
  2 siblings, 0 replies; 5+ messages in thread
From: amirmohammad.eftekhar @ 2026-10-22 21:51 UTC (permalink / raw)
  To: seanjc, pbonzini
  Cc: kvm, linux-kernel, amirmohammadeftekhar, Amirmohammad Eftekhar

From: Amirmohammad Eftekhar <amirmohammad.eftekhar@cispa.de>

nested_check_guest_non_reg_state() only checks that guest_activity_state is
one of ACTIVE/HLT/WAIT_SIPI; it does not enforce the SDM's requirement that
the activity state indicate the active state when the interruptibility-state
field blocks by STI or MOV SS.  KVM cannot rely on hardware to catch the
miss: prepare_vmcs02() never writes GUEST_ACTIVITY_STATE, so vmcs02 always
carries the active state and the physical VMLAUNCH cannot reject the illegal
combination.  Add the cross-check.

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

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index b25216862740..6e2ec1912f12 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -3311,6 +3311,11 @@ static int nested_check_guest_non_reg_state(struct vmcs12 *vmcs12)
 	       vmcs12->guest_activity_state != GUEST_ACTIVITY_WAIT_SIPI))
 		return -EINVAL;
 
+	if (CC(vmcs12->guest_activity_state != GUEST_ACTIVITY_ACTIVE &&
+	       (vmcs12->guest_interruptibility_info &
+		(GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS))))
+		return -EINVAL;
+
 	return 0;
 }
 
-- 
2.34.1


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

* [PATCH v3 2/2] KVM: nVMX: Reject nested VM-entry in wait-for-SIPI with a pending event injection
  2026-10-22 21:42 ` Sean Christopherson
  2026-10-22 21:51   ` [PATCH v3 0/2] KVM: nVMX: Add the activity-state cross-checks VM-entry requires amirmohammad.eftekhar
  2026-10-22 21:51   ` [PATCH v3 1/2] KVM: nVMX: Reject nested VM-entry in a non-active state blocked by STI/MOV-SS amirmohammad.eftekhar
@ 2026-10-22 21:51   ` amirmohammad.eftekhar
  2 siblings, 0 replies; 5+ messages in thread
From: amirmohammad.eftekhar @ 2026-10-22 21:51 UTC (permalink / raw)
  To: seanjc, pbonzini
  Cc: kvm, linux-kernel, amirmohammadeftekhar, Amirmohammad Eftekhar

From: Amirmohammad Eftekhar <amirmohammad.eftekhar@cispa.de>

The SDM allows no interruptions in the wait-for-SIPI activity state, but
nested_check_guest_non_reg_state() accepts a vmcs12 with WAIT_SIPI and a valid
VM-entry interruption-information field.  Hardware does not catch it: KVM
emulates wait-for-SIPI in software only after a successful entry (the mp_state
= INIT_RECEIVED arm) while the injection is copied into vmcs02, so the physical
VMLAUNCH sees {active, valid injection} -- a legal pair -- and succeeds.  From
L1's point of view a VMLAUNCH that bare metal rejects with a VM-entry failure
instead succeeds, with L2 parked in wait-for-SIPI holding a stale
VM_ENTRY_INTR_INFO.  Reject the combination.

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

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 6e2ec1912f12..d98d33234e9f 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -3316,6 +3316,10 @@ static int nested_check_guest_non_reg_state(struct vmcs12 *vmcs12)
 		(GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS))))
 		return -EINVAL;
 
+	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.34.1


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

end of thread, other threads:[~2026-10-22 21:52 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-22 21:12 [PATCH] KVM: nVMX: Reject nested VM-entry in wait-for-SIPI with a pending event injection Amirmohammad Eftekhar
2026-10-22 21:42 ` Sean Christopherson
2026-10-22 21:51   ` [PATCH v3 0/2] KVM: nVMX: Add the activity-state cross-checks VM-entry requires amirmohammad.eftekhar
2026-10-22 21:51   ` [PATCH v3 1/2] KVM: nVMX: Reject nested VM-entry in a non-active state blocked by STI/MOV-SS amirmohammad.eftekhar
2026-10-22 21:51   ` [PATCH v3 2/2] KVM: nVMX: Reject nested VM-entry in wait-for-SIPI with a pending event injection amirmohammad.eftekhar

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

all inboxes | Powered by JetHome®