[PATCH 09/19] KVM: x86: Add #CP support in guest exception classification.

From: Yang Weijiang
Date: Thu Jun 16 2022 - 04:50:16 EST


Add handling for Control Protection (#CP) exceptions, vector 21, used
and introduced by Intel's Control-Flow Enforcement Technology (CET).
relevant CET violation case. See Intel's SDM for details.

Signed-off-by: Yang Weijiang <weijiang.yang@xxxxxxxxx>
Message-Id: <20210203113421.5759-5-weijiang.yang@xxxxxxxxx>
Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>
---
arch/x86/include/uapi/asm/kvm.h | 1 +
arch/x86/kvm/vmx/nested.c | 2 +-
arch/x86/kvm/x86.c | 10 +++++++---
arch/x86/kvm/x86.h | 13 ++++++++++---
4 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
index 50a4e787d5e6..69146e7436af 100644
--- a/arch/x86/include/uapi/asm/kvm.h
+++ b/arch/x86/include/uapi/asm/kvm.h
@@ -32,6 +32,7 @@
#define MC_VECTOR 18
#define XM_VECTOR 19
#define VE_VECTOR 20
+#define CP_VECTOR 21

/* Select x86 specific features in <linux/kvm.h> */
#define __KVM_HAVE_PIT
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 7d8cd0ebcc75..01fe23c6fa49 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -2819,7 +2819,7 @@ static int nested_check_vm_entry_controls(struct kvm_vcpu *vcpu,
/* VM-entry interruption-info field: deliver error code */
should_have_error_code =
intr_type == INTR_TYPE_HARD_EXCEPTION && prot_mode &&
- x86_exception_has_error_code(vector);
+ x86_exception_has_error_code(vcpu, vector);
if (CC(has_error_code != should_have_error_code))
return -EINVAL;

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 506454e17afc..40749e47cda7 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -511,11 +511,15 @@ EXPORT_SYMBOL_GPL(kvm_spurious_fault);
#define EXCPT_CONTRIBUTORY 1
#define EXCPT_PF 2

-static int exception_class(int vector)
+static int exception_class(struct kvm_vcpu *vcpu, int vector)
{
switch (vector) {
case PF_VECTOR:
return EXCPT_PF;
+ case CP_VECTOR:
+ if (vcpu->arch.cr4_guest_rsvd_bits & X86_CR4_CET)
+ return EXCPT_BENIGN;
+ return EXCPT_CONTRIBUTORY;
case DE_VECTOR:
case TS_VECTOR:
case NP_VECTOR:
@@ -659,8 +663,8 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
return;
}
- class1 = exception_class(prev_nr);
- class2 = exception_class(nr);
+ class1 = exception_class(vcpu, prev_nr);
+ class2 = exception_class(vcpu, nr);
if ((class1 == EXCPT_CONTRIBUTORY && class2 == EXCPT_CONTRIBUTORY)
|| (class1 == EXCPT_PF && class2 != EXCPT_BENIGN)) {
/*
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index 501b884b8cc4..b9b1fff6d97a 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -148,13 +148,20 @@ static inline bool is_64_bit_hypercall(struct kvm_vcpu *vcpu)
return vcpu->arch.guest_state_protected || is_64_bit_mode(vcpu);
}

-static inline bool x86_exception_has_error_code(unsigned int vector)
+static inline bool x86_exception_has_error_code(struct kvm_vcpu *vcpu,
+ unsigned int vector)
{
static u32 exception_has_error_code = BIT(DF_VECTOR) | BIT(TS_VECTOR) |
BIT(NP_VECTOR) | BIT(SS_VECTOR) | BIT(GP_VECTOR) |
- BIT(PF_VECTOR) | BIT(AC_VECTOR);
+ BIT(PF_VECTOR) | BIT(AC_VECTOR) | BIT(CP_VECTOR);

- return (1U << vector) & exception_has_error_code;
+ if (!((1U << vector) & exception_has_error_code))
+ return false;
+
+ if (vector == CP_VECTOR)
+ return !(vcpu->arch.cr4_guest_rsvd_bits & X86_CR4_CET);
+
+ return true;
}

static inline bool mmu_is_nested(struct kvm_vcpu *vcpu)
--
2.27.0