@@ -17,6 +17,7 @@ struct kvmi_interception {
bool restore_interception;
struct kvmi_monitor_interception breakpoint;
struct kvmi_monitor_interception cr3w;
+ struct kvmi_monitor_interception descriptor;
};
struct kvm_vcpu_arch_introspection {
@@ -48,6 +49,7 @@ bool kvmi_monitor_cr3w_intercept(struct kvm_vcpu *vcpu, bool enable);
void kvmi_enter_guest(struct kvm_vcpu *vcpu);
void kvmi_xsetbv_event(struct kvm_vcpu *vcpu, u8 xcr,
u64 old_value, u64 new_value);
+bool kvmi_monitor_desc_intercept(struct kvm_vcpu *vcpu, bool enable);
bool kvmi_descriptor_event(struct kvm_vcpu *vcpu, u8 descriptor, bool write);
#else /* CONFIG_KVM_INTROSPECTION */
@@ -64,6 +66,8 @@ static inline bool kvmi_monitor_cr3w_intercept(struct kvm_vcpu *vcpu,
static inline void kvmi_enter_guest(struct kvm_vcpu *vcpu) { }
static inline void kvmi_xsetbv_event(struct kvm_vcpu *vcpu, u8 xcr,
u64 old_value, u64 new_value) { }
+static inline bool kvmi_monitor_desc_intercept(struct kvm_vcpu *vcpu,
+ bool enable) { return false; }
static inline bool kvmi_descriptor_event(struct kvm_vcpu *vcpu, u8 descriptor,
bool write) { return true; }
@@ -286,12 +286,52 @@ static void kvmi_arch_disable_cr3w_intercept(struct kvm_vcpu *vcpu)
vcpu->arch.kvmi->cr3w.kvm_intercepted = false;
}
+/*
+ * Returns true if one side (kvm or kvmi) tries to disable the descriptor
+ * interception while the other side is still tracking it.
+ */
+bool kvmi_monitor_desc_intercept(struct kvm_vcpu *vcpu, bool enable)
+{
+ struct kvmi_interception *arch_vcpui = READ_ONCE(vcpu->arch.kvmi);
+
+ return (arch_vcpui && arch_vcpui->descriptor.monitor_fct(vcpu, enable));
+}
+EXPORT_SYMBOL(kvmi_monitor_desc_intercept);
+
+static bool monitor_desc_fct_kvmi(struct kvm_vcpu *vcpu, bool enable)
+{
+ vcpu->arch.kvmi->descriptor.kvmi_intercepted = enable;
+
+ if (enable)
+ vcpu->arch.kvmi->descriptor.kvm_intercepted =
+ kvm_x86_ops.desc_intercepted(vcpu);
+ else if (vcpu->arch.kvmi->descriptor.kvm_intercepted)
+ return true;
+
+ return false;
+}
+
+static bool monitor_desc_fct_kvm(struct kvm_vcpu *vcpu, bool enable)
+{
+ if (!vcpu->arch.kvmi->descriptor.kvmi_intercepted)
+ return false;
+
+ vcpu->arch.kvmi->descriptor.kvm_intercepted = enable;
+
+ if (!enable)
+ return true;
+
+ return false;
+}
+
static int kvmi_control_desc_intercept(struct kvm_vcpu *vcpu, bool enable)
{
if (!kvm_x86_ops.desc_ctrl_supported())
return -KVM_EOPNOTSUPP;
+ vcpu->arch.kvmi->descriptor.monitor_fct = monitor_desc_fct_kvmi;
kvm_x86_ops.control_desc_intercept(vcpu, enable);
+ vcpu->arch.kvmi->descriptor.monitor_fct = monitor_desc_fct_kvm;
return 0;
}
@@ -299,6 +339,9 @@ static int kvmi_control_desc_intercept(struct kvm_vcpu *vcpu, bool enable)
static void kvmi_arch_disable_desc_intercept(struct kvm_vcpu *vcpu)
{
kvmi_control_desc_intercept(vcpu, false);
+
+ vcpu->arch.kvmi->descriptor.kvmi_intercepted = false;
+ vcpu->arch.kvmi->descriptor.kvm_intercepted = false;
}
int kvmi_arch_cmd_control_intercept(struct kvm_vcpu *vcpu,
@@ -370,11 +413,13 @@ bool kvmi_arch_vcpu_alloc_interception(struct kvm_vcpu *vcpu)
arch_vcpui->breakpoint.monitor_fct = monitor_bp_fct_kvm;
arch_vcpui->cr3w.monitor_fct = monitor_cr3w_fct_kvm;
+ arch_vcpui->descriptor.monitor_fct = monitor_desc_fct_kvm;
/*
* paired with:
* - kvmi_monitor_bp_intercept()
* - kvmi_monitor_cr3w_intercept()
+ * - kvmi_monitor_desc_intercept()
*/
smp_wmb();
WRITE_ONCE(vcpu->arch.kvmi, arch_vcpui);
@@ -1670,6 +1670,9 @@ static void svm_control_desc_intercept(struct kvm_vcpu *vcpu, bool enable)
{
struct vcpu_svm *svm = to_svm(vcpu);
+ if (kvmi_monitor_desc_intercept(vcpu, enable))
+ return;
+
if (enable) {
svm_set_intercept(svm, INTERCEPT_STORE_IDTR);
svm_set_intercept(svm, INTERCEPT_STORE_GDTR);
@@ -3130,6 +3130,9 @@ static void vmx_control_desc_intercept(struct kvm_vcpu *vcpu, bool enable)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
+ if (kvmi_monitor_desc_intercept(vcpu, enable))
+ return;
+
if (enable)
secondary_exec_controls_setbit(vmx, SECONDARY_EXEC_DESC);
else