2022-10-20 09:58:38

by Maxim Levitsky

[permalink] [raw]
Subject: [PATCH 0/4] nSVM: fix L0 crash if L2 has shutdown condtion which L1 doesn't intercept

Recently while trying to fix some unit tests I found another CVE in SVM nested code.



In 'shutdown_interception' vmexit handler we call kvm_vcpu_reset.



However if running nested and L1 doesn't intercept shutdown, we will still end

up running this function and trigger a bug in it.



The bug is that this function resets the 'vcpu->arch.hflags' without properly

leaving the nested state, which leaves the vCPU in inconsistent state, which

later triggers a kernel panic in SVM code.



The same bug can likely be triggered by sending INIT via local apic to a vCPU

which runs a nested guest.



On VMX we are lucky that the issue can't happen because VMX always intercepts

triple faults, thus triple fault in L2 will always be redirected to L1.

Plus the 'handle_triple_fault' of VMX doesn't reset the vCPU.



INIT IPI can't happen on VMX either because INIT events are masked while in

VMX mode.



Best regards,

Maxim Levitsky



Maxim Levitsky (4):

KVM: x86: nSVM: leave nested mode on vCPU free

KVM: x86: nSVM: harden svm_free_nested against freeing vmcb02 while

still in use

KVM: x86: add kvm_leave_nested

KVM: x86: forcibly leave nested mode on vCPU reset



arch/x86/kvm/svm/nested.c | 6 +++---

arch/x86/kvm/svm/svm.c | 1 +

arch/x86/kvm/vmx/nested.c | 3 ---

arch/x86/kvm/x86.c | 9 ++++++++-

4 files changed, 12 insertions(+), 7 deletions(-)



--

2.26.3





2022-10-20 09:59:19

by Maxim Levitsky

[permalink] [raw]
Subject: [PATCH 1/4] KVM: x86: nSVM: leave nested mode on vCPU free

If the VM was terminated while nested, we free the nested state
while the vCPU still is in nested mode.

Soon a warning will be added for this condition.

Cc: [email protected]
Signed-off-by: Maxim Levitsky <[email protected]>
---
arch/x86/kvm/svm/svm.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 58f0077d935799..958faa8807f52b 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1439,6 +1439,7 @@ static void svm_vcpu_free(struct kvm_vcpu *vcpu)
*/
svm_clear_current_vmcb(svm->vmcb);

+ svm_leave_nested(vcpu);
svm_free_nested(svm);

sev_free_vcpu(vcpu);
--
2.26.3

2022-10-20 09:59:59

by Maxim Levitsky

[permalink] [raw]
Subject: [PATCH 3/4] KVM: x86: add kvm_leave_nested

Wrap a call to nested_ops->leave_nested into a function.

Cc: [email protected]
Signed-off-by: Maxim Levitsky <[email protected]>
---
arch/x86/kvm/svm/nested.c | 3 ---
arch/x86/kvm/vmx/nested.c | 3 ---
arch/x86/kvm/x86.c | 8 +++++++-
3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index b02a3a1792f194..7354f0035a691d 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -1146,9 +1146,6 @@ void svm_free_nested(struct vcpu_svm *svm)
svm->nested.initialized = false;
}

-/*
- * Forcibly leave nested mode in order to be able to reset the VCPU later on.
- */
void svm_leave_nested(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 8f67a9c4a28706..a66c5e276ab408 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -6440,9 +6440,6 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
return kvm_state.size;
}

-/*
- * Forcibly leave nested mode in order to be able to reset the VCPU later on.
- */
void vmx_leave_nested(struct kvm_vcpu *vcpu)
{
if (is_guest_mode(vcpu)) {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 4bd5f8a751de91..d86a8aae1471d3 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -628,6 +628,12 @@ static void kvm_queue_exception_vmexit(struct kvm_vcpu *vcpu, unsigned int vecto
ex->payload = payload;
}

+/* Forcibly leave the nested mode in cases like a vCPU reset */
+static void kvm_leave_nested(struct kvm_vcpu *vcpu)
+{
+ kvm_x86_ops.nested_ops->leave_nested(vcpu);
+}
+
static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
unsigned nr, bool has_error, u32 error_code,
bool has_payload, unsigned long payload, bool reinject)
@@ -5200,7 +5206,7 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,

if (events->flags & KVM_VCPUEVENT_VALID_SMM) {
if (!!(vcpu->arch.hflags & HF_SMM_MASK) != events->smi.smm) {
- kvm_x86_ops.nested_ops->leave_nested(vcpu);
+ kvm_leave_nested(vcpu);
kvm_smm_changed(vcpu, events->smi.smm);
}

--
2.26.3