When emulating L2 instructions, svm_check_intercept() checks whether a write to CR0 should trigger a synthesized #VMEXIT with SVM_EXIT_CR0_SEL_WRITE. However, it does not check whether L1 enabled the intercept for SVM_EXIT_WRITE_CR0, which has higher priority according to the APM (24593—Rev. 3.42—March 2024, Table 15-7): When both selective and non-selective CR0-write intercepts are active at the same time, the non-selective intercept takes priority. With respect to exceptions, the priority of this inter Make sure L1 does NOT intercept SVM_EXIT_WRITE_CR0 before checking if SVM_EXIT_CR0_SEL_WRITE needs to be injected. Fixes: cfec82cb7d31 ("KVM: SVM: Add intercept check for emulated cr accesses") Cc: stable@vger.kernel Signed-off-by: Yosry Ahmed --- arch/x86/kvm/svm/svm.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 9ea0ff136e299..4f79c4d837535 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4533,12 +4533,22 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu, if (info->intercept == x86_intercept_cr_write) icpt_info.exit_code += info->modrm_reg; + /* + * If the write is indeed to CR0, check whether the exit_code + * needs to be converted to SVM_EXIT_CR0_SEL_WRITE. Intercepting + * SVM_EXIT_WRITE_CR0 has higher priority than + * SVM_EXIT_CR0_SEL_WRITE, so this is only relevant if L1 sets + * INTERCEPT_SELECTIVE_CR0 but not INTERCEPT_CR0_WRITE. + */ if (icpt_info.exit_code != SVM_EXIT_WRITE_CR0 || - info->intercept == x86_intercept_clts) + vmcb12_is_intercept(&svm->nested.ctl, + INTERCEPT_CR0_WRITE) || + !(vmcb12_is_intercept(&svm->nested.ctl, + INTERCEPT_SELECTIVE_CR0))) break; - if (!(vmcb12_is_intercept(&svm->nested.ctl, - INTERCEPT_SELECTIVE_CR0))) + /* CLTS never triggers INTERCEPT_SELECTIVE_CR0 */ + if (info->intercept == x86_intercept_clts) break; /* LMSW always triggers INTERCEPT_SELECTIVE_CR0 */ -- 2.51.1.821.gb6fe4d2222-goog