Skip to content

Commit 73a8e77

Browse files
Maxim Levitskygregkh
authored andcommitted
KVM: nVMX: Check vmcs12->guest_ia32_debugctl on nested VM-Enter
[ Upstream commit 095686e ] Add a consistency check for L2's guest_ia32_debugctl, as KVM only supports a subset of hardware functionality, i.e. KVM can't rely on hardware to detect illegal/unsupported values. Failure to check the vmcs12 value would allow the guest to load any harware-supported value while running L2. Take care to exempt BTF and LBR from the validity check in order to match KVM's behavior for writes via WRMSR, but without clobbering vmcs12. Even if VM_EXIT_SAVE_DEBUG_CONTROLS is set in vmcs12, L1 can reasonably expect that vmcs12->guest_ia32_debugctl will not be modified if writes to the MSR are being intercepted. Arguably, KVM _should_ update vmcs12 if VM_EXIT_SAVE_DEBUG_CONTROLS is set *and* writes to MSR_IA32_DEBUGCTLMSR are not being intercepted by L1, but that would incur non-trivial complexity and wouldn't change the fact that KVM's handling of DEBUGCTL is blatantly broken. I.e. the extra complexity is not worth carrying. Cc: stable@vger.kernel.org Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> Co-developed-by: Sean Christopherson <seanjc@google.com> Link: https://lore.kernel.org/r/20250610232010.162191-7-seanjc@google.com Stable-dep-of: 7d0cce6 ("KVM: VMX: Wrap all accesses to IA32_DEBUGCTL with getter/setter APIs") Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 6c6a7c6 commit 73a8e77

File tree

3 files changed

+15
-5
lines changed

3 files changed

+15
-5
lines changed

arch/x86/kvm/vmx/nested.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2653,7 +2653,8 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
26532653
if (vmx->nested.nested_run_pending &&
26542654
(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS)) {
26552655
kvm_set_dr(vcpu, 7, vmcs12->guest_dr7);
2656-
vmcs_write64(GUEST_IA32_DEBUGCTL, vmcs12->guest_ia32_debugctl);
2656+
vmcs_write64(GUEST_IA32_DEBUGCTL, vmcs12->guest_ia32_debugctl &
2657+
vmx_get_supported_debugctl(vcpu, false));
26572658
} else {
26582659
kvm_set_dr(vcpu, 7, vcpu->arch.dr7);
26592660
vmcs_write64(GUEST_IA32_DEBUGCTL, vmx->nested.pre_vmenter_debugctl);
@@ -3135,7 +3136,8 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu,
31353136
return -EINVAL;
31363137

31373138
if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS) &&
3138-
CC(!kvm_dr7_valid(vmcs12->guest_dr7)))
3139+
(CC(!kvm_dr7_valid(vmcs12->guest_dr7)) ||
3140+
CC(!vmx_is_valid_debugctl(vcpu, vmcs12->guest_ia32_debugctl, false))))
31393141
return -EINVAL;
31403142

31413143
if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PAT) &&
@@ -4576,6 +4578,12 @@ static void sync_vmcs02_to_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
45764578
(vmcs12->vm_entry_controls & ~VM_ENTRY_IA32E_MODE) |
45774579
(vm_entry_controls_get(to_vmx(vcpu)) & VM_ENTRY_IA32E_MODE);
45784580

4581+
/*
4582+
* Note! Save DR7, but intentionally don't grab DEBUGCTL from vmcs02.
4583+
* Writes to DEBUGCTL that aren't intercepted by L1 are immediately
4584+
* propagated to vmcs12 (see vmx_set_msr()), as the value loaded into
4585+
* vmcs02 doesn't strictly track vmcs12.
4586+
*/
45794587
if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_DEBUG_CONTROLS)
45804588
vmcs12->guest_dr7 = vcpu->arch.dr7;
45814589

arch/x86/kvm/vmx/vmx.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2173,7 +2173,7 @@ static u64 nested_vmx_truncate_sysenter_addr(struct kvm_vcpu *vcpu,
21732173
return (unsigned long)data;
21742174
}
21752175

2176-
static u64 vmx_get_supported_debugctl(struct kvm_vcpu *vcpu, bool host_initiated)
2176+
u64 vmx_get_supported_debugctl(struct kvm_vcpu *vcpu, bool host_initiated)
21772177
{
21782178
u64 debugctl = 0;
21792179

@@ -2192,8 +2192,7 @@ static u64 vmx_get_supported_debugctl(struct kvm_vcpu *vcpu, bool host_initiated
21922192
return debugctl;
21932193
}
21942194

2195-
static bool vmx_is_valid_debugctl(struct kvm_vcpu *vcpu, u64 data,
2196-
bool host_initiated)
2195+
bool vmx_is_valid_debugctl(struct kvm_vcpu *vcpu, u64 data, bool host_initiated)
21972196
{
21982197
u64 invalid;
21992198

arch/x86/kvm/vmx/vmx.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,9 @@ static inline void vmx_set_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr,
435435

436436
void vmx_update_cpu_dirty_logging(struct kvm_vcpu *vcpu);
437437

438+
u64 vmx_get_supported_debugctl(struct kvm_vcpu *vcpu, bool host_initiated);
439+
bool vmx_is_valid_debugctl(struct kvm_vcpu *vcpu, u64 data, bool host_initiated);
440+
438441
/*
439442
* Note, early Intel manuals have the write-low and read-high bitmap offsets
440443
* the wrong way round. The bitmaps control MSRs 0x00000000-0x00001fff and

0 commit comments

Comments
 (0)