From: Nicușor Cîțu <ncitu@xxxxxxxxxxxxxxx> These will be used to implement a tiny agent which runs in the context of an introspected guest and uses virtualized exceptions (#VE) and alternate EPT views (VMFUNC #0) to filter converted VMEXITS. The events of interested will be suppressed (after some appropriate guest-side handling) while the rest will be sent to the introspector via a VMCALL. Signed-off-by: Nicușor Cîțu <ncitu@xxxxxxxxxxxxxxx> --- arch/x86/kvm/svm.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/vmx.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 17902a9e518d..d6b5baa513c3 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -4738,6 +4738,41 @@ static int avic_unaccelerated_access_interception(struct vcpu_svm *svm) return ret; } +#ifdef CONFIG_KVM_INTROSPECTION +static int descriptor_access_interception(struct vcpu_svm *svm) +{ + struct kvm_vcpu *vcpu = &svm->vcpu; + struct vmcb_control_area *c = &svm->vmcb->control; + + switch (c->exit_code) { + case SVM_EXIT_IDTR_READ: + case SVM_EXIT_IDTR_WRITE: + kvmi_descriptor_event(vcpu, c->exit_info_1, 0, + KVMI_DESC_IDTR, c->exit_code == SVM_EXIT_IDTR_WRITE); + break; + case SVM_EXIT_GDTR_READ: + case SVM_EXIT_GDTR_WRITE: + kvmi_descriptor_event(vcpu, c->exit_info_1, 0, + KVMI_DESC_GDTR, c->exit_code == SVM_EXIT_GDTR_WRITE); + break; + case SVM_EXIT_LDTR_READ: + case SVM_EXIT_LDTR_WRITE: + kvmi_descriptor_event(vcpu, c->exit_info_1, 0, + KVMI_DESC_LDTR, c->exit_code == SVM_EXIT_LDTR_WRITE); + break; + case SVM_EXIT_TR_READ: + case SVM_EXIT_TR_WRITE: + kvmi_descriptor_event(vcpu, c->exit_info_1, 0, + KVMI_DESC_TR, c->exit_code == SVM_EXIT_TR_WRITE); + break; + default: + break; + } + + return 1; +} +#endif /* CONFIG_KVM_INTROSPECTION */ + static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = { [SVM_EXIT_READ_CR0] = cr_interception, [SVM_EXIT_READ_CR3] = cr_interception, @@ -4803,6 +4838,16 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = { [SVM_EXIT_RSM] = rsm_interception, [SVM_EXIT_AVIC_INCOMPLETE_IPI] = avic_incomplete_ipi_interception, [SVM_EXIT_AVIC_UNACCELERATED_ACCESS] = avic_unaccelerated_access_interception, +#ifdef CONFIG_KVM_INTROSPECTION + [SVM_EXIT_IDTR_READ] = descriptor_access_interception, + [SVM_EXIT_GDTR_READ] = descriptor_access_interception, + [SVM_EXIT_LDTR_READ] = descriptor_access_interception, + [SVM_EXIT_TR_READ] = descriptor_access_interception, + [SVM_EXIT_IDTR_WRITE] = descriptor_access_interception, + [SVM_EXIT_GDTR_WRITE] = descriptor_access_interception, + [SVM_EXIT_LDTR_WRITE] = descriptor_access_interception, + [SVM_EXIT_TR_WRITE] = descriptor_access_interception, +#endif /* CONFIG_KVM_INTROSPECTION */ }; static void dump_vmcb(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 72d4b521fed7..b976903c925c 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -7293,6 +7293,35 @@ static int handle_set_cr4(struct kvm_vcpu *vcpu, unsigned long val) static int handle_desc(struct kvm_vcpu *vcpu) { +#ifdef CONFIG_KVM_INTROSPECTION + struct vcpu_vmx *vmx = to_vmx(vcpu); + u32 exit_reason = vmx->exit_reason; + unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION); + u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO); + unsigned char store = (vmx_instruction_info >> 29) & 0x1; + unsigned char descriptor = 0; + + if (exit_reason == EXIT_REASON_GDTR_IDTR) { + if ((vmx_instruction_info >> 28) & 0x1) + descriptor = KVMI_DESC_IDTR; + else + descriptor = KVMI_DESC_GDTR; + } else { + if ((vmx_instruction_info >> 28) & 0x1) + descriptor = KVMI_DESC_TR; + else + descriptor = KVMI_DESC_LDTR; + } + + /* + * For now, this function returns false only when the guest + * is ungracefully stopped (crashed) by the introspection tool. + */ + if (!kvmi_descriptor_event(vcpu, vmx_instruction_info, + exit_qualification, descriptor, store)) + return false; +#endif /* CONFIG_KVM_INTROSPECTION */ + WARN_ON(!(vcpu->arch.cr4 & X86_CR4_UMIP)); return kvm_emulate_instruction(vcpu, 0) == EMULATE_DONE; }