Skip to content

Commit c931ea9

Browse files
yosrym93gregkh
authored andcommitted
KVM: nSVM: Always recalculate LBR MSR intercepts in svm_update_lbrv()
commit fbe5e5f upstream. svm_update_lbrv() is called when MSR_IA32_DEBUGCTLMSR is updated, and on nested transitions where LBRV is used. It checks whether LBRV enablement needs to be changed in the current VMCB, and if it does, it also recalculate intercepts to LBR MSRs. However, there are cases where intercepts need to be updated even when LBRV enablement doesn't. Example scenario: - L1 has MSR_IA32_DEBUGCTLMSR cleared. - L1 runs L2 without LBR_CTL_ENABLE (no LBRV). - L2 sets DEBUGCTLMSR_LBR in MSR_IA32_DEBUGCTLMSR, svm_update_lbrv() sets LBR_CTL_ENABLE in VMCB02 and disables intercepts to LBR MSRs. - L2 exits to L1, svm_update_lbrv() is not called on this transition. - L1 clears MSR_IA32_DEBUGCTLMSR, svm_update_lbrv() finds that LBR_CTL_ENABLE is already cleared in VMCB01 and does nothing. - Intercepts remain disabled, L1 reads to LBR MSRs read the host MSRs. Fix it by always recalculating intercepts in svm_update_lbrv(). Fixes: 1d5a1b5 ("KVM: x86: nSVM: correctly virtualize LBR msrs when L2 is running") Cc: stable@vger.kernel.org Signed-off-by: Yosry Ahmed <yosry.ahmed@linux.dev> Link: https://patch.msgid.link/20251108004524.1600006-3-yosry.ahmed@linux.dev Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Yosry Ahmed <yosry.ahmed@linux.dev> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent d8a64e5 commit c931ea9

1 file changed

Lines changed: 19 additions & 10 deletions

File tree

arch/x86/kvm/svm/svm.c

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,26 +1014,30 @@ static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
10141014
!intercept, !intercept);
10151015
}
10161016

1017-
void svm_enable_lbrv(struct kvm_vcpu *vcpu)
1017+
static void __svm_enable_lbrv(struct kvm_vcpu *vcpu)
10181018
{
10191019
struct vcpu_svm *svm = to_svm(vcpu);
10201020

10211021
svm->vmcb->control.virt_ext |= LBR_CTL_ENABLE_MASK;
1022-
svm_recalc_lbr_msr_intercepts(vcpu);
10231022

10241023
/* Move the LBR msrs to the vmcb02 so that the guest can see them. */
10251024
if (is_guest_mode(vcpu))
10261025
svm_copy_lbrs(svm->vmcb, svm->vmcb01.ptr);
10271026
}
10281027

1029-
static void svm_disable_lbrv(struct kvm_vcpu *vcpu)
1028+
void svm_enable_lbrv(struct kvm_vcpu *vcpu)
1029+
{
1030+
__svm_enable_lbrv(vcpu);
1031+
svm_recalc_lbr_msr_intercepts(vcpu);
1032+
}
1033+
1034+
static void __svm_disable_lbrv(struct kvm_vcpu *vcpu)
10301035
{
10311036
struct vcpu_svm *svm = to_svm(vcpu);
10321037

10331038
KVM_BUG_ON(sev_es_guest(vcpu->kvm), vcpu->kvm);
10341039

10351040
svm->vmcb->control.virt_ext &= ~LBR_CTL_ENABLE_MASK;
1036-
svm_recalc_lbr_msr_intercepts(vcpu);
10371041

10381042
/*
10391043
* Move the LBR msrs back to the vmcb01 to avoid copying them
@@ -1062,13 +1066,18 @@ void svm_update_lbrv(struct kvm_vcpu *vcpu)
10621066
(is_guest_mode(vcpu) && guest_can_use(vcpu, X86_FEATURE_LBRV) &&
10631067
(svm->nested.ctl.virt_ext & LBR_CTL_ENABLE_MASK));
10641068

1065-
if (enable_lbrv == current_enable_lbrv)
1066-
return;
1069+
if (enable_lbrv && !current_enable_lbrv)
1070+
__svm_enable_lbrv(vcpu);
1071+
else if (!enable_lbrv && current_enable_lbrv)
1072+
__svm_disable_lbrv(vcpu);
10671073

1068-
if (enable_lbrv)
1069-
svm_enable_lbrv(vcpu);
1070-
else
1071-
svm_disable_lbrv(vcpu);
1074+
/*
1075+
* During nested transitions, it is possible that the current VMCB has
1076+
* LBR_CTL set, but the previous LBR_CTL had it cleared (or vice versa).
1077+
* In this case, even though LBR_CTL does not need an update, intercepts
1078+
* do, so always recalculate the intercepts here.
1079+
*/
1080+
svm_recalc_lbr_msr_intercepts(vcpu);
10721081
}
10731082

10741083
void disable_nmi_singlestep(struct vcpu_svm *svm)

0 commit comments

Comments
 (0)