The AMD APM states that VMRUN, VMLOAD, VMSAVE, CLGI, VMMCALL, and INVLPGA instructions should generate a #UD when EFER.SVME is cleared. Currently, when VMLOAD, VMSAVE, or CLGI are executed in L1 with EFER.SVME cleared, no #UD is generated in certain cases. This is because the intercepts for these instructions are cleared based on whether or not vls or vgif is enabled. The #UD fails to be generated when the intercepts are absent. Fix the missing #UD generation by ensuring that all relevant instructions have intercepts set when SVME.EFER is disabled. VMMCALL is special because KVM's ABI is that VMCALL/VMMCALL are always supported for L1 and never fault. Signed-off-by: Kevin Cheng --- arch/x86/kvm/svm/svm.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 92a2faff1ccc8..92a66b62cfabd 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -243,6 +243,8 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer) if (svm_gp_erratum_intercept && !sev_guest(vcpu->kvm)) set_exception_intercept(svm, GP_VECTOR); } + + kvm_make_request(KVM_REQ_RECALC_INTERCEPTS, vcpu); } svm->vmcb->save.efer = efer | EFER_SVME; @@ -976,6 +978,7 @@ void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu) static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); + u64 efer = vcpu->arch.efer; /* * Intercept INVPCID if shadow paging is enabled to sync/free shadow @@ -996,7 +999,13 @@ static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu) svm_set_intercept(svm, INTERCEPT_RDTSCP); } - if (guest_cpuid_is_intel_compatible(vcpu)) { + /* + * Intercept instructions that #UD if EFER.SVME=0, as SVME must be set even + * when running the guest, i.e. hardware will only ever see EFER.SVME=1. + */ + if (guest_cpuid_is_intel_compatible(vcpu) || !(efer & EFER_SVME)) { + svm_set_intercept(svm, INTERCEPT_CLGI); + svm_set_intercept(svm, INTERCEPT_STGI); svm_set_intercept(svm, INTERCEPT_VMLOAD); svm_set_intercept(svm, INTERCEPT_VMSAVE); svm->vmcb->control.virt_ext &= ~VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK; -- 2.52.0.457.g6b5491de43-goog