Skip to content

Commit 5e1b0b0

Browse files
sean-jcgregkh
authored andcommitted
KVM: SVM: Manually context switch DEBUGCTL if LBR virtualization is disabled
commit 4332658 upstream. Manually load the guest's DEBUGCTL prior to VMRUN (and restore the host's value on #VMEXIT) if it diverges from the host's value and LBR virtualization is disabled, as hardware only context switches DEBUGCTL if LBR virtualization is fully enabled. Running the guest with the host's value has likely been mildly problematic for quite some time, e.g. it will result in undesirable behavior if BTF diverges (with the caveat that KVM now suppresses guest BTF due to lack of support). But the bug became fatal with the introduction of Bus Lock Trap ("Detect" in kernel paralance) support for AMD (commit 408eb74 ("x86/bus_lock: Add support for AMD")), as a bus lock in the guest will trigger an unexpected #DB. Note, suppressing the bus lock #DB, i.e. simply resuming the guest without injecting a #DB, is not an option. It wouldn't address the general issue with DEBUGCTL, e.g. for things like BTF, and there are other guest-visible side effects if BusLockTrap is left enabled. If BusLockTrap is disabled, then DR6.BLD is reserved-to-1; any attempts to clear it by software are ignored. But if BusLockTrap is enabled, software can clear DR6.BLD: Software enables bus lock trap by setting DebugCtl MSR[BLCKDB] (bit 2) to 1. When bus lock trap is enabled, ... The processor indicates that this #DB was caused by a bus lock by clearing DR6[BLD] (bit 11). DR6[11] previously had been defined to be always 1. and clearing DR6.BLD is "sticky" in that it's not set (i.e. lowered) by other #DBs: All other #DB exceptions leave DR6[BLD] unmodified E.g. leaving BusLockTrap enable can confuse a legacy guest that writes '0' to reset DR6. Reported-by: rangemachine@gmail.com Reported-by: whanos@sergal.fun Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219787 Closes: https://lore.kernel.org/all/bug-219787-28872@https.bugzilla.kernel.org%2F Cc: Ravi Bangoria <ravi.bangoria@amd.com> Cc: stable@vger.kernel.org Reviewed-and-tested-by: Ravi Bangoria <ravi.bangoria@amd.com> Link: https://lore.kernel.org/r/20250227222411.3490595-5-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 4e5e47f commit 5e1b0b0

1 file changed

Lines changed: 14 additions & 0 deletions

File tree

arch/x86/kvm/svm/svm.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4277,6 +4277,16 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu,
42774277
clgi();
42784278
kvm_load_guest_xsave_state(vcpu);
42794279

4280+
/*
4281+
* Hardware only context switches DEBUGCTL if LBR virtualization is
4282+
* enabled. Manually load DEBUGCTL if necessary (and restore it after
4283+
* VM-Exit), as running with the host's DEBUGCTL can negatively affect
4284+
* guest state and can even be fatal, e.g. due to Bus Lock Detect.
4285+
*/
4286+
if (!(svm->vmcb->control.virt_ext & LBR_CTL_ENABLE_MASK) &&
4287+
vcpu->arch.host_debugctl != svm->vmcb->save.dbgctl)
4288+
update_debugctlmsr(svm->vmcb->save.dbgctl);
4289+
42804290
kvm_wait_lapic_expire(vcpu);
42814291

42824292
/*
@@ -4304,6 +4314,10 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu,
43044314
if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
43054315
kvm_before_interrupt(vcpu, KVM_HANDLING_NMI);
43064316

4317+
if (!(svm->vmcb->control.virt_ext & LBR_CTL_ENABLE_MASK) &&
4318+
vcpu->arch.host_debugctl != svm->vmcb->save.dbgctl)
4319+
update_debugctlmsr(vcpu->arch.host_debugctl);
4320+
43074321
kvm_load_host_xsave_state(vcpu);
43084322
stgi();
43094323

0 commit comments

Comments
 (0)