From mboxrd@z Thu Jan 1 00:00:00 1970 From: Yang Zhang Subject: Re: [RFC PATCH 4/4] KVM: vmx: add support for emulating UMIP Date: Wed, 13 Jul 2016 17:21:23 +0800 Message-ID: <8f893604-1e80-2979-bc87-45a049238e58@gmail.com> References: <1468351223-3250-1-git-send-email-pbonzini@redhat.com> <1468351223-3250-5-git-send-email-pbonzini@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit To: Paolo Bonzini , linux-kernel@vger.kernel.org, kvm@vger.kernel.org Return-path: In-Reply-To: <1468351223-3250-5-git-send-email-pbonzini@redhat.com> Sender: linux-kernel-owner@vger.kernel.org List-Id: kvm.vger.kernel.org On 2016/7/13 3:20, Paolo Bonzini wrote: > UMIP (User-Mode Instruction Prevention) is a feature of future > Intel processors (Cannonlake?) that blocks SLDT, SGDT, STR, SIDT > and SMSW from user-mode processes. > > On Intel systems it's *almost* possible to emulate it; it slows > down the instructions when they're executed in ring 0, but they > are really never executed in practice. The catch is that SMSW > doesn't cause a vmexit, and hence SMSW will not fault. > > When UMIP is enabled but not supported by the host, descriptor table > exits are enabled, and the emulator takes care of injecting a #GP when > any of SLDT, SGDT, STR, SIDT are encountered. > > Signed-off-by: Paolo Bonzini > --- > arch/x86/include/asm/vmx.h | 1 + > arch/x86/include/uapi/asm/vmx.h | 4 ++++ > arch/x86/kvm/vmx.c | 36 ++++++++++++++++++++++++++++++++++-- > 3 files changed, 39 insertions(+), 2 deletions(-) > > diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h > index 14c63c7e8337..8b95f0ec0190 100644 > --- a/arch/x86/include/asm/vmx.h > +++ b/arch/x86/include/asm/vmx.h > @@ -60,6 +60,7 @@ > */ > #define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 > #define SECONDARY_EXEC_ENABLE_EPT 0x00000002 > +#define SECONDARY_EXEC_DESC 0x00000004 > #define SECONDARY_EXEC_RDTSCP 0x00000008 > #define SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE 0x00000010 > #define SECONDARY_EXEC_ENABLE_VPID 0x00000020 > diff --git a/arch/x86/include/uapi/asm/vmx.h b/arch/x86/include/uapi/asm/vmx.h > index 5b15d94a33f8..2f9a69b9559c 100644 > --- a/arch/x86/include/uapi/asm/vmx.h > +++ b/arch/x86/include/uapi/asm/vmx.h > @@ -65,6 +65,8 @@ > #define EXIT_REASON_TPR_BELOW_THRESHOLD 43 > #define EXIT_REASON_APIC_ACCESS 44 > #define EXIT_REASON_EOI_INDUCED 45 > +#define EXIT_REASON_GDTR_IDTR 46 > +#define EXIT_REASON_LDTR_TR 47 > #define EXIT_REASON_EPT_VIOLATION 48 > #define EXIT_REASON_EPT_MISCONFIG 49 > #define EXIT_REASON_INVEPT 50 > @@ -114,6 +116,8 @@ > { EXIT_REASON_MCE_DURING_VMENTRY, "MCE_DURING_VMENTRY" }, \ > { EXIT_REASON_TPR_BELOW_THRESHOLD, "TPR_BELOW_THRESHOLD" }, \ > { EXIT_REASON_APIC_ACCESS, "APIC_ACCESS" }, \ > + { EXIT_REASON_GDTR_IDTR, "GDTR_IDTR" }, \ > + { EXIT_REASON_LDTR_TR, "LDTR_TR" }, \ > { EXIT_REASON_EPT_VIOLATION, "EPT_VIOLATION" }, \ > { EXIT_REASON_EPT_MISCONFIG, "EPT_MISCONFIG" }, \ > { EXIT_REASON_INVEPT, "INVEPT" }, \ > diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c > index b133fc3d6a7d..0706e363c5e3 100644 > --- a/arch/x86/kvm/vmx.c > +++ b/arch/x86/kvm/vmx.c > @@ -3342,6 +3342,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) > SECONDARY_EXEC_ENABLE_EPT | > SECONDARY_EXEC_UNRESTRICTED_GUEST | > SECONDARY_EXEC_PAUSE_LOOP_EXITING | > + SECONDARY_EXEC_DESC | > SECONDARY_EXEC_RDTSCP | > SECONDARY_EXEC_ENABLE_INVPCID | > SECONDARY_EXEC_APIC_REGISTER_VIRT | > @@ -3967,6 +3968,14 @@ static int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) > (to_vmx(vcpu)->rmode.vm86_active ? > KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON); > > + if ((cr4 & X86_CR4_UMIP) && !boot_cpu_has(X86_FEATURE_UMIP)) { > + vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL, > + SECONDARY_EXEC_DESC); > + hw_cr4 &= ~X86_CR4_UMIP; > + } else > + vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL, > + SECONDARY_EXEC_DESC); > + Since the faults based on privilege level have priority over VM exits. So we don't need to enable/disable SECONDARY_EXEC_DESC dynamically. Instead, we can set it unconditionally. > if (cr4 & X86_CR4_VMXE) { > /* > * To use VMXON (and later other VMX instructions), a guest > @@ -4913,6 +4922,11 @@ static u32 vmx_exec_control(struct vcpu_vmx *vmx) > static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx) > { > u32 exec_control = vmcs_config.cpu_based_2nd_exec_ctrl; > + > + /* SECONDARY_EXEC_DESC is enabled/disabled on writes to CR4.UMIP, > + * in vmx_set_cr4. */ > + exec_control &= ~SECONDARY_EXEC_DESC; > + > if (!cpu_need_virtualize_apic_accesses(&vmx->vcpu)) > exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; > if (vmx->vpid == 0) > @@ -5649,6 +5663,12 @@ static void handle_clts(struct kvm_vcpu *vcpu) > vmx_set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~X86_CR0_TS)); > } > > +static int handle_desc(struct kvm_vcpu *vcpu) > +{ > + WARN_ON(!(vcpu->arch.cr4 & X86_CR4_UMIP)); I think WARN_ON is too heavy since a malicious guest may trigger it always. > + return emulate_instruction(vcpu, 0) == EMULATE_DONE; > +} > + > static int handle_cr(struct kvm_vcpu *vcpu) > { > unsigned long exit_qualification, val; > @@ -7705,6 +7731,8 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { > [EXIT_REASON_XSETBV] = handle_xsetbv, > [EXIT_REASON_TASK_SWITCH] = handle_task_switch, > [EXIT_REASON_MCE_DURING_VMENTRY] = handle_machine_check, > + [EXIT_REASON_GDTR_IDTR] = handle_desc, > + [EXIT_REASON_LDTR_TR] = handle_desc, > [EXIT_REASON_EPT_VIOLATION] = handle_ept_violation, > [EXIT_REASON_EPT_MISCONFIG] = handle_ept_misconfig, > [EXIT_REASON_PAUSE_INSTRUCTION] = handle_pause, > @@ -7972,6 +8000,8 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu) > return nested_cpu_has(vmcs12, CPU_BASED_MOV_DR_EXITING); > case EXIT_REASON_IO_INSTRUCTION: > return nested_vmx_exit_handled_io(vcpu, vmcs12); > + case EXIT_REASON_GDTR_IDTR: case EXIT_REASON_LDTR_TR: > + return nested_cpu_has2(vmcs12, SECONDARY_EXEC_DESC); > case EXIT_REASON_MSR_READ: > case EXIT_REASON_MSR_WRITE: > return nested_vmx_exit_handled_msr(vcpu, vmcs12, exit_reason); > @@ -8597,7 +8627,8 @@ static bool vmx_xsaves_supported(void) > > static bool vmx_umip_emulated(void) > { > - return false; > + return vmcs_config.cpu_based_2nd_exec_ctrl & > + SECONDARY_EXEC_DESC; > } > > static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx) > @@ -9173,7 +9204,8 @@ static void vmcs_set_secondary_exec_control(u32 new_ctl) > u32 mask = > SECONDARY_EXEC_SHADOW_VMCS | > SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | > - SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; > + SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | > + SECONDARY_EXEC_DESC; > > u32 cur_ctl = vmcs_read32(SECONDARY_VM_EXEC_CONTROL); > > -- Yang Alibaba Cloud Computing