All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] KVM: x86: Nested fixes (mostly #DF/#TF)
@ 2022-04-07  0:23 Sean Christopherson
  2022-04-07  0:23 ` [PATCH 1/3] KVM: x86: Drop WARNs that assert a triple fault never "escapes" from L2 Sean Christopherson
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Sean Christopherson @ 2022-04-07  0:23 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
	Joerg Roedel, kvm, linux-kernel, Chenyi Qiang

Patch 1 removes an assertion that is going to fail miserably once KVM
allows save/restore of pending triple faults.

Patches 2 and 3 are fixes for edge cases for nVMX related to saving exit
info on failed VM-Entry, #DF and triple fault, that in all likelihood no
one cares about.

Sean Christopherson (3):
  KVM: x86: Drop WARNs that assert a triple fault never "escapes" from
    L2
  KVM: nVMX: Leave most VM-Exit info fields unmodified on failed
    VM-Entry
  KVM: nVMX: Clear IDT vectoring on nested VM-Exit for double/triple
    fault

 arch/x86/kvm/svm/nested.c |  3 ---
 arch/x86/kvm/vmx/nested.c | 48 ++++++++++++++++++++++++++++++---------
 arch/x86/kvm/vmx/vmcs.h   |  5 ++++
 3 files changed, 42 insertions(+), 14 deletions(-)


base-commit: 7d4cda14f55ae6998220aaecd2ab00e20d0e8f57
-- 
2.35.1.1094.g7c7d902a7c-goog


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

* [PATCH 1/3] KVM: x86: Drop WARNs that assert a triple fault never "escapes" from L2
  2022-04-07  0:23 [PATCH 0/3] KVM: x86: Nested fixes (mostly #DF/#TF) Sean Christopherson
@ 2022-04-07  0:23 ` Sean Christopherson
  2022-04-07  0:23 ` [PATCH 2/3] KVM: nVMX: Leave most VM-Exit info fields unmodified on failed VM-Entry Sean Christopherson
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Sean Christopherson @ 2022-04-07  0:23 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
	Joerg Roedel, kvm, linux-kernel, Chenyi Qiang

Remove WARNs that sanity check that KVM never lets a triple fault for L2
escape and incorrectly end up in L1.  In normal operation, the sanity
check is perfectly valid, but it incorrectly assumes that it's impossible
for userspace to induce KVM_REQ_TRIPLE_FAULT without bouncing through
KVM_RUN (which guarantees kvm_check_nested_state() will see and handle
the triple fault).

The WARN can currently be triggered if userspace injects a machine check
while L2 is active and CR4.MCE=0.  And a future fix to allow save/restore
of KVM_REQ_TRIPLE_FAULT, e.g. so that a synthesized triple fault isn't
lost on migration, will make it trivially easy for userspace to trigger
the WARN.

Clearing KVM_REQ_TRIPLE_FAULT when forcibly leaving guest mode is
tempting, but wrong, especially if/when the request is saved/restored,
e.g. if userspace restores events (including a triple fault) and then
restores nested state (which may forcibly leave guest mode).  Ignoring
the fact that KVM doesn't currently provide the necessary APIs, it's
userspace's responsibility to manage pending events during save/restore.

  ------------[ cut here ]------------
  WARNING: CPU: 7 PID: 1399 at arch/x86/kvm/vmx/nested.c:4522 nested_vmx_vmexit+0x7fe/0xd90 [kvm_intel]
  Modules linked in: kvm_intel kvm irqbypass
  CPU: 7 PID: 1399 Comm: state_test Not tainted 5.17.0-rc3+ #808
  Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
  RIP: 0010:nested_vmx_vmexit+0x7fe/0xd90 [kvm_intel]
  Call Trace:
   <TASK>
   vmx_leave_nested+0x30/0x40 [kvm_intel]
   vmx_set_nested_state+0xca/0x3e0 [kvm_intel]
   kvm_arch_vcpu_ioctl+0xf49/0x13e0 [kvm]
   kvm_vcpu_ioctl+0x4b9/0x660 [kvm]
   __x64_sys_ioctl+0x83/0xb0
   do_syscall_64+0x3b/0xc0
   entry_SYSCALL_64_after_hwframe+0x44/0xae
   </TASK>
  ---[ end trace 0000000000000000 ]---

Fixes: cb6a32c2b877 ("KVM: x86: Handle triple fault in L2 without killing L1")
Cc: stable@vger.kernel.org
Cc: Chenyi Qiang <chenyi.qiang@intel.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/kvm/svm/nested.c | 3 ---
 arch/x86/kvm/vmx/nested.c | 3 ---
 2 files changed, 6 deletions(-)

diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index c1ef7867797a..bed5e1692cef 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -894,9 +894,6 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
 	struct kvm_host_map map;
 	int rc;
 
-	/* Triple faults in L2 should never escape. */
-	WARN_ON_ONCE(kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu));
-
 	rc = kvm_vcpu_map(vcpu, gpa_to_gfn(svm->nested.vmcb12_gpa), &map);
 	if (rc) {
 		if (rc == -EINVAL)
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 50d83b9f8067..ec4cbf583921 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -4514,9 +4514,6 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
 	/* trying to cancel vmlaunch/vmresume is a bug */
 	WARN_ON_ONCE(vmx->nested.nested_run_pending);
 
-	/* Similarly, triple faults in L2 should never escape. */
-	WARN_ON_ONCE(kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu));
-
 	if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) {
 		/*
 		 * KVM_REQ_GET_NESTED_STATE_PAGES is also used to map
-- 
2.35.1.1094.g7c7d902a7c-goog


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

* [PATCH 2/3] KVM: nVMX: Leave most VM-Exit info fields unmodified on failed VM-Entry
  2022-04-07  0:23 [PATCH 0/3] KVM: x86: Nested fixes (mostly #DF/#TF) Sean Christopherson
  2022-04-07  0:23 ` [PATCH 1/3] KVM: x86: Drop WARNs that assert a triple fault never "escapes" from L2 Sean Christopherson
@ 2022-04-07  0:23 ` Sean Christopherson
  2022-04-07  0:23 ` [PATCH 3/3] KVM: nVMX: Clear IDT vectoring on nested VM-Exit for double/triple fault Sean Christopherson
  2022-04-08 16:50 ` [PATCH 0/3] KVM: x86: Nested fixes (mostly #DF/#TF) Paolo Bonzini
  3 siblings, 0 replies; 7+ messages in thread
From: Sean Christopherson @ 2022-04-07  0:23 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
	Joerg Roedel, kvm, linux-kernel, Chenyi Qiang

Don't modify vmcs12 exit fields except EXIT_REASON and EXIT_QUALIFICATION
when performing a nested VM-Exit due to failed VM-Entry.  Per the SDM,
only the two aformentioned fields are filled and "All other VM-exit
information fields are unmodified".

Fixes: 4704d0befb07 ("KVM: nVMX: Exiting from L2 to L1")
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/kvm/vmx/nested.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index ec4cbf583921..9a4938955bad 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -4198,12 +4198,12 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
 	if (to_vmx(vcpu)->exit_reason.enclave_mode)
 		vmcs12->vm_exit_reason |= VMX_EXIT_REASONS_SGX_ENCLAVE_MODE;
 	vmcs12->exit_qualification = exit_qualification;
-	vmcs12->vm_exit_intr_info = exit_intr_info;
-
-	vmcs12->idt_vectoring_info_field = 0;
-	vmcs12->vm_exit_instruction_len = vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
-	vmcs12->vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
 
+	/*
+	 * On VM-Exit due to a failed VM-Entry, the VMCS isn't marked launched
+	 * and only EXIT_REASON and EXIT_QUALIFICATION are updated, all other
+	 * exit info fields are unmodified.
+	 */
 	if (!(vmcs12->vm_exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY)) {
 		vmcs12->launch_state = 1;
 
@@ -4215,8 +4215,13 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
 		 * Transfer the event that L0 or L1 may wanted to inject into
 		 * L2 to IDT_VECTORING_INFO_FIELD.
 		 */
+		vmcs12->idt_vectoring_info_field = 0;
 		vmcs12_save_pending_event(vcpu, vmcs12);
 
+		vmcs12->vm_exit_intr_info = exit_intr_info;
+		vmcs12->vm_exit_instruction_len = vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+		vmcs12->vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
+
 		/*
 		 * According to spec, there's no need to store the guest's
 		 * MSRs if the exit is due to a VM-entry failure that occurs
-- 
2.35.1.1094.g7c7d902a7c-goog


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

* [PATCH 3/3] KVM: nVMX: Clear IDT vectoring on nested VM-Exit for double/triple fault
  2022-04-07  0:23 [PATCH 0/3] KVM: x86: Nested fixes (mostly #DF/#TF) Sean Christopherson
  2022-04-07  0:23 ` [PATCH 1/3] KVM: x86: Drop WARNs that assert a triple fault never "escapes" from L2 Sean Christopherson
  2022-04-07  0:23 ` [PATCH 2/3] KVM: nVMX: Leave most VM-Exit info fields unmodified on failed VM-Entry Sean Christopherson
@ 2022-04-07  0:23 ` Sean Christopherson
  2022-04-07  8:02   ` Xiaoyao Li
  2022-04-08 16:50 ` [PATCH 0/3] KVM: x86: Nested fixes (mostly #DF/#TF) Paolo Bonzini
  3 siblings, 1 reply; 7+ messages in thread
From: Sean Christopherson @ 2022-04-07  0:23 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
	Joerg Roedel, kvm, linux-kernel, Chenyi Qiang

Clear the IDT vectoring field in vmcs12 on next VM-Exit due to a double
or triple fault.  Per the SDM, a VM-Exit isn't considered to occur during
event delivery if the exit is due to an intercepted double fault or a
triple fault.  Opportunistically move the default clearing (no event
"pending") into the helper so that it's more obvious that KVM does indeed
handle this case.

Note, the double fault case is worded rather wierdly in the SDM:

  The original event results in a double-fault exception that causes the
  VM exit directly.

Temporarily ignoring injected events, double faults can _only_ occur if
an exception occurs while attempting to deliver a different exception,
i.e. there's _always_ an original event.  And for injected double fault,
while there's no original event, injected events are never subject to
interception.

Presumably the SDM is calling out that a the vectoring info will be valid
if a different exit occurs after a double fault, e.g. if a #PF occurs and
is intercepted while vectoring #DF, then the vectoring info will show the
double fault.  In other words, the clause can simply be read as:

  The VM exit is caused by a double-fault exception.

Fixes: 4704d0befb07 ("KVM: nVMX: Exiting from L2 to L1")
Cc: Chenyi Qiang <chenyi.qiang@intel.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/kvm/vmx/nested.c | 32 ++++++++++++++++++++++++++++----
 arch/x86/kvm/vmx/vmcs.h   |  5 +++++
 2 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 9a4938955bad..a6688663da4d 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -3691,12 +3691,34 @@ vmcs12_guest_cr4(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
 }
 
 static void vmcs12_save_pending_event(struct kvm_vcpu *vcpu,
-				      struct vmcs12 *vmcs12)
+				      struct vmcs12 *vmcs12,
+				      u32 vm_exit_reason, u32 exit_intr_info)
 {
 	u32 idt_vectoring;
 	unsigned int nr;
 
-	if (vcpu->arch.exception.injected) {
+	/*
+	 * Per the SDM, VM-Exits due to double and triple faults are never
+	 * considered to occur during event delivery, even if the double/triple
+	 * fault is the result of an escalating vectoring issue.
+	 *
+	 * Note, the SDM qualifies the double fault behavior with "The original
+	 * event results in a double-fault exception".  It's unclear why the
+	 * qualification exists since exits due to double fault can occur only
+	 * while vectoring a different exception (injected events are never
+	 * subject to interception), i.e. there's _always_ an original event.
+	 *
+	 * The SDM also uses NMI as a confusing example for the "original event
+	 * causes the VM exit directly" clause.  NMI isn't special in any way,
+	 * the same rule applies to all events that cause an exit directly.
+	 * NMI is an odd choice for the example because NMIs can only occur on
+	 * instruction boundaries, i.e. they _can't_ occur during vectoring.
+	 */
+	if ((u16)vm_exit_reason == EXIT_REASON_TRIPLE_FAULT ||
+	    ((u16)vm_exit_reason == EXIT_REASON_EXCEPTION_NMI &&
+	     is_double_fault(exit_intr_info))) {
+		vmcs12->idt_vectoring_info_field = 0;
+	} else if (vcpu->arch.exception.injected) {
 		nr = vcpu->arch.exception.nr;
 		idt_vectoring = nr | VECTORING_INFO_VALID_MASK;
 
@@ -3729,6 +3751,8 @@ static void vmcs12_save_pending_event(struct kvm_vcpu *vcpu,
 			idt_vectoring |= INTR_TYPE_EXT_INTR;
 
 		vmcs12->idt_vectoring_info_field = idt_vectoring;
+	} else {
+		vmcs12->idt_vectoring_info_field = 0;
 	}
 }
 
@@ -4215,8 +4239,8 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
 		 * Transfer the event that L0 or L1 may wanted to inject into
 		 * L2 to IDT_VECTORING_INFO_FIELD.
 		 */
-		vmcs12->idt_vectoring_info_field = 0;
-		vmcs12_save_pending_event(vcpu, vmcs12);
+		vmcs12_save_pending_event(vcpu, vmcs12,
+					  vm_exit_reason, exit_intr_info);
 
 		vmcs12->vm_exit_intr_info = exit_intr_info;
 		vmcs12->vm_exit_instruction_len = vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
diff --git a/arch/x86/kvm/vmx/vmcs.h b/arch/x86/kvm/vmx/vmcs.h
index e325c290a816..2b9d7a7e83f7 100644
--- a/arch/x86/kvm/vmx/vmcs.h
+++ b/arch/x86/kvm/vmx/vmcs.h
@@ -104,6 +104,11 @@ static inline bool is_breakpoint(u32 intr_info)
 	return is_exception_n(intr_info, BP_VECTOR);
 }
 
+static inline bool is_double_fault(u32 intr_info)
+{
+	return is_exception_n(intr_info, DF_VECTOR);
+}
+
 static inline bool is_page_fault(u32 intr_info)
 {
 	return is_exception_n(intr_info, PF_VECTOR);
-- 
2.35.1.1094.g7c7d902a7c-goog


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

* Re: [PATCH 3/3] KVM: nVMX: Clear IDT vectoring on nested VM-Exit for double/triple fault
  2022-04-07  0:23 ` [PATCH 3/3] KVM: nVMX: Clear IDT vectoring on nested VM-Exit for double/triple fault Sean Christopherson
@ 2022-04-07  8:02   ` Xiaoyao Li
  2022-04-07  8:42     ` Xiaoyao Li
  0 siblings, 1 reply; 7+ messages in thread
From: Xiaoyao Li @ 2022-04-07  8:02 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini
  Cc: Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel, kvm,
	linux-kernel, Chenyi Qiang

On 4/7/2022 8:23 AM, Sean Christopherson wrote:
> Clear the IDT vectoring field in vmcs12 on next VM-Exit due to a double
> or triple fault.  Per the SDM, a VM-Exit isn't considered to occur during
> event delivery if the exit is due to an intercepted double fault or a
> triple fault.  Opportunistically move the default clearing (no event
> "pending") into the helper so that it's more obvious that KVM does indeed
> handle this case.
> 
> Note, the double fault case is worded rather wierdly in the SDM:
> 
>    The original event results in a double-fault exception that causes the
>    VM exit directly.
> 
> Temporarily ignoring injected events, double faults can _only_ occur if
> an exception occurs while attempting to deliver a different exception,
> i.e. there's _always_ an original event.  And for injected double fault,
> while there's no original event, injected events are never subject to
> interception.
> 
> Presumably the SDM is calling out that a the vectoring info will be valid
> if a different exit occurs after a double fault, e.g. if a #PF occurs and
> is intercepted while vectoring #DF, then the vectoring info will show the
> double fault.  

Wouldn't it be a tripe fault exit in this case?

> In other words, the clause can simply be read as:
> 
>    The VM exit is caused by a double-fault exception.


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

* Re: [PATCH 3/3] KVM: nVMX: Clear IDT vectoring on nested VM-Exit for double/triple fault
  2022-04-07  8:02   ` Xiaoyao Li
@ 2022-04-07  8:42     ` Xiaoyao Li
  0 siblings, 0 replies; 7+ messages in thread
From: Xiaoyao Li @ 2022-04-07  8:42 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini
  Cc: Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel, kvm,
	linux-kernel, Chenyi Qiang

On 4/7/2022 4:02 PM, Xiaoyao Li wrote:
> On 4/7/2022 8:23 AM, Sean Christopherson wrote:
>> Clear the IDT vectoring field in vmcs12 on next VM-Exit due to a double
>> or triple fault.  Per the SDM, a VM-Exit isn't considered to occur during
>> event delivery if the exit is due to an intercepted double fault or a
>> triple fault.  Opportunistically move the default clearing (no event
>> "pending") into the helper so that it's more obvious that KVM does indeed
>> handle this case.
>>
>> Note, the double fault case is worded rather wierdly in the SDM:
>>
>>    The original event results in a double-fault exception that causes the
>>    VM exit directly.
>>
>> Temporarily ignoring injected events, double faults can _only_ occur if
>> an exception occurs while attempting to deliver a different exception,
>> i.e. there's _always_ an original event.  And for injected double fault,
>> while there's no original event, injected events are never subject to
>> interception.
>>
>> Presumably the SDM is calling out that a the vectoring info will be valid
>> if a different exit occurs after a double fault, e.g. if a #PF occurs and
>> is intercepted while vectoring #DF, then the vectoring info will show the
>> double fault. 
> 
> Wouldn't it be a tripe fault exit in this case?

It won't since #PF is intercepted by exception bitmap in your case.

>> In other words, the clause can simply be read as:
>>
>>    The VM exit is caused by a double-fault exception.
> 


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

* Re: [PATCH 0/3] KVM: x86: Nested fixes (mostly #DF/#TF)
  2022-04-07  0:23 [PATCH 0/3] KVM: x86: Nested fixes (mostly #DF/#TF) Sean Christopherson
                   ` (2 preceding siblings ...)
  2022-04-07  0:23 ` [PATCH 3/3] KVM: nVMX: Clear IDT vectoring on nested VM-Exit for double/triple fault Sean Christopherson
@ 2022-04-08 16:50 ` Paolo Bonzini
  3 siblings, 0 replies; 7+ messages in thread
From: Paolo Bonzini @ 2022-04-08 16:50 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel, kvm,
	linux-kernel, Chenyi Qiang

Queued, thanks.

Paolo



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

end of thread, other threads:[~2022-04-08 16:50 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-07  0:23 [PATCH 0/3] KVM: x86: Nested fixes (mostly #DF/#TF) Sean Christopherson
2022-04-07  0:23 ` [PATCH 1/3] KVM: x86: Drop WARNs that assert a triple fault never "escapes" from L2 Sean Christopherson
2022-04-07  0:23 ` [PATCH 2/3] KVM: nVMX: Leave most VM-Exit info fields unmodified on failed VM-Entry Sean Christopherson
2022-04-07  0:23 ` [PATCH 3/3] KVM: nVMX: Clear IDT vectoring on nested VM-Exit for double/triple fault Sean Christopherson
2022-04-07  8:02   ` Xiaoyao Li
2022-04-07  8:42     ` Xiaoyao Li
2022-04-08 16:50 ` [PATCH 0/3] KVM: x86: Nested fixes (mostly #DF/#TF) Paolo Bonzini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.