FAILED: patch "[PATCH] KVM: nVMX: Check vmcs12->guest_ia32_debugctl on nested" failed to apply to 6.12-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 095686e6fcb4150f0a55b1a25987fad3d8af58d6
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2025081223-parameter-cope-c338@gregkh' --subject-prefix 'PATCH 6.12.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 095686e6fcb4150f0a55b1a25987fad3d8af58d6 Mon Sep 17 00:00:00 2001
From: Maxim Levitsky <[email protected]>
Date: Tue, 10 Jun 2025 16:20:08 -0700
Subject: [PATCH] KVM: nVMX: Check vmcs12->guest_ia32_debugctl on nested
VM-Enter
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.
arch/x86/kvm/vmx/nested.c +10 -2
@@ -2663,7 +2663,8 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,if (vmx->nested.nested_run_pending && (vmcs12->vm_entry_controls &VM_ENTRY_LOAD_DEBUG_CONTROLS )) {kvm_set_dr (vcpu,7 , vmcs12->guest_dr7); -vmcs_write64 (GUEST_IA32_DEBUGCTL , vmcs12->guest_ia32_debugctl); +vmcs_write64 (GUEST_IA32_DEBUGCTL , vmcs12->guest_ia32_debugctl & +vmx_get_supported_debugctl (vcpu, false)); }else {kvm_set_dr (vcpu,7 , vcpu->arch.dr7);vmcs_write64 (GUEST_IA32_DEBUGCTL , vmx->nested.pre_vmenter_debugctl);
@@ -3156,7 +3157,8 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu,return -EINVAL ;if ((vmcs12->vm_entry_controls &VM_ENTRY_LOAD_DEBUG_CONTROLS ) && -CC (!kvm_dr7_valid (vmcs12->guest_dr7))) + (CC (!kvm_dr7_valid (vmcs12->guest_dr7)) || +CC (!vmx_is_valid_debugctl (vcpu, vmcs12->guest_ia32_debugctl, false))))return -EINVAL ; if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PAT) &&
@@ -4608,6 +4610,12 @@ static void sync_vmcs02_to_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) (vmcs12->vm_entry_controls & ~VM_ENTRY_IA32E_MODE ) | (vm_entry_controls_get (to_vmx (vcpu)) &VM_ENTRY_IA32E_MODE ); +/* +* Note! Save DR7, but intentionally don't grab DEBUGCTL from vmcs02. +* Writes to DEBUGCTL that aren't intercepted by L1 are immediately +* propagated to vmcs12 (see vmx_set_msr()), as the value loaded into +* vmcs02 doesn't strictly track vmcs12. +*/ if (vmcs12->vm_exit_controls &VM_EXIT_SAVE_DEBUG_CONTROLS ) vmcs12->guest_dr7 = vcpu->arch.dr7;
arch/x86/kvm/vmx/vmx.c +2 -3
@@ -2174,7 +2174,7 @@ static u64 nested_vmx_truncate_sysenter_addr(struct kvm_vcpu *vcpu,return (unsigned long )data; } -static u64 vmx_get_supported_debugctl (struct kvm_vcpu *vcpu,bool host_initiated) +u64 vmx_get_supported_debugctl (struct kvm_vcpu *vcpu,bool host_initiated) {u64 debugctl =0 ;
@@ -2193,8 +2193,7 @@ static u64 vmx_get_supported_debugctl(struct kvm_vcpu *vcpu, bool host_initiatedreturn debugctl; } -static bool vmx_is_valid_debugctl (struct kvm_vcpu *vcpu,u64 data, -bool host_initiated) +bool vmx_is_valid_debugctl (struct kvm_vcpu *vcpu,u64 data,bool host_initiated) {u64 invalid;
arch/x86/kvm/vmx/vmx.h +3 -0
@@ -414,6 +414,9 @@ static inline void vmx_set_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr,void vmx_update_cpu_dirty_logging (struct kvm_vcpu *vcpu); +u64 vmx_get_supported_debugctl (struct kvm_vcpu *vcpu,bool host_initiated); +bool vmx_is_valid_debugctl (struct kvm_vcpu *vcpu,u64 data,bool host_initiated); +/* * Note, early Intel manuals have the write-low and read-high bitmap offsets * the wrong way round. The bitmaps control MSRs 0x00000000-0x00001fff and
Sasha Levin
maintainerPATCH 1/2 KVM: VMX: Extract checking of guest's DEBUGCTL into helper
From: Sean Christopherson <[email protected]>
[ Upstream commit 8a4351ac302cd8c19729ba2636acfd0467c22ae8 ]
Move VMX's logic to check DEBUGCTL values into a standalone helper so that the code can be used by nested VM-Enter to apply the same logic to the value being loaded from vmcs12.
KVM needs to explicitly check vmcs12->guest_ia32_debugctl on nested VM-Enter, as hardware may support features that KVM does not, i.e. relying on hardware to detect invalid guest state will result in false negatives. Unfortunately, that means applying KVM's funky suppression of BTF and LBR to vmcs12 so as not to break existing guests.
No functional change intended.
Stable-dep-of: 095686e6fcb4 ("KVM: nVMX: Check vmcs12->guest_ia32_debugctl on nested VM-Enter")
--- arch/x86/kvm/vmx/vmx.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-)
arch/x86/kvm/vmx/vmx.c +17 -12
@@ -2188,6 +2188,19 @@ static u64 vmx_get_supported_debugctl(struct kvm_vcpu *vcpu, bool host_initiatedreturn debugctl; } +static bool vmx_is_valid_debugctl (struct kvm_vcpu *vcpu,u64 data, +bool host_initiated) +{ +u64 invalid; + + invalid = data & ~vmx_get_supported_debugctl (vcpu, host_initiated); +if (invalid & (DEBUGCTLMSR_BTF |DEBUGCTLMSR_LBR )) { +kvm_pr_unimpl_wrmsr (vcpu,MSR_IA32_DEBUGCTLMSR , data); + invalid &= ~(DEBUGCTLMSR_BTF |DEBUGCTLMSR_LBR ); + } +return !invalid; +} +/* * Writes msr value into the appropriate "register". * Returns 0 on success, non-0 otherwise.
@@ -2256,19 +2269,12 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) }vmcs_writel (GUEST_SYSENTER_ESP , data);break ; -case MSR_IA32_DEBUGCTLMSR : { -u64 invalid; - - invalid = data & ~vmx_get_supported_debugctl (vcpu, msr_info->host_initiated); -if (invalid & (DEBUGCTLMSR_BTF |DEBUGCTLMSR_LBR )) { -kvm_pr_unimpl_wrmsr (vcpu, msr_index, data); - data &= ~(DEBUGCTLMSR_BTF |DEBUGCTLMSR_LBR ); - invalid &= ~(DEBUGCTLMSR_BTF |DEBUGCTLMSR_LBR ); - } - -if (invalid) +case MSR_IA32_DEBUGCTLMSR : +if (!vmx_is_valid_debugctl (vcpu, data, msr_info->host_initiated))return 1 ; + data &=vmx_get_supported_debugctl (vcpu, msr_info->host_initiated); +if (is_guest_mode (vcpu) &&get_vmcs12 (vcpu)->vm_exit_controls &VM_EXIT_SAVE_DEBUG_CONTROLS )get_vmcs12 (vcpu)->guest_ia32_debugctl = data;
@@ -2278,7 +2284,6 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) (data & DEBUGCTLMSR_LBR))intel_pmu_create_guest_lbr_event (vcpu);return 0 ; - }case MSR_IA32_BNDCFGS : if (!kvm_mpx_supported() || (!msr_info->host_initiated &&
Signature · 1 line
2.39.5
Sasha Levin
maintainerPATCH 2/2 KVM: nVMX: Check vmcs12->guest_ia32_debugctl on nested VM-Enter
From: Maxim Levitsky <[email protected]>
[ Upstream commit 095686e6fcb4150f0a55b1a25987fad3d8af58d6 ]
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.
--- arch/x86/kvm/vmx/nested.c | 12 ++++++++++-- arch/x86/kvm/vmx/vmx.c | 5 ++--- arch/x86/kvm/vmx/vmx.h | 3 +++ 3 files changed, 15 insertions(+), 5 deletions(-)
arch/x86/kvm/vmx/nested.c +10 -2
@@ -2653,7 +2653,8 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,if (vmx->nested.nested_run_pending && (vmcs12->vm_entry_controls &VM_ENTRY_LOAD_DEBUG_CONTROLS )) {kvm_set_dr (vcpu,7 , vmcs12->guest_dr7); -vmcs_write64 (GUEST_IA32_DEBUGCTL , vmcs12->guest_ia32_debugctl); +vmcs_write64 (GUEST_IA32_DEBUGCTL , vmcs12->guest_ia32_debugctl & +vmx_get_supported_debugctl (vcpu, false)); }else {kvm_set_dr (vcpu,7 , vcpu->arch.dr7);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,return -EINVAL ;if ((vmcs12->vm_entry_controls &VM_ENTRY_LOAD_DEBUG_CONTROLS ) && -CC (!kvm_dr7_valid (vmcs12->guest_dr7))) + (CC (!kvm_dr7_valid (vmcs12->guest_dr7)) || +CC (!vmx_is_valid_debugctl (vcpu, vmcs12->guest_ia32_debugctl, false))))return -EINVAL ; 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) (vmcs12->vm_entry_controls & ~VM_ENTRY_IA32E_MODE ) | (vm_entry_controls_get (to_vmx (vcpu)) &VM_ENTRY_IA32E_MODE ); +/* +* Note! Save DR7, but intentionally don't grab DEBUGCTL from vmcs02. +* Writes to DEBUGCTL that aren't intercepted by L1 are immediately +* propagated to vmcs12 (see vmx_set_msr()), as the value loaded into +* vmcs02 doesn't strictly track vmcs12. +*/ if (vmcs12->vm_exit_controls &VM_EXIT_SAVE_DEBUG_CONTROLS ) vmcs12->guest_dr7 = vcpu->arch.dr7;
arch/x86/kvm/vmx/vmx.c +2 -3
@@ -2173,7 +2173,7 @@ static u64 nested_vmx_truncate_sysenter_addr(struct kvm_vcpu *vcpu,return (unsigned long )data; } -static u64 vmx_get_supported_debugctl (struct kvm_vcpu *vcpu,bool host_initiated) +u64 vmx_get_supported_debugctl (struct kvm_vcpu *vcpu,bool host_initiated) {u64 debugctl =0 ;
@@ -2188,8 +2188,7 @@ static u64 vmx_get_supported_debugctl(struct kvm_vcpu *vcpu, bool host_initiatedreturn debugctl; } -static bool vmx_is_valid_debugctl (struct kvm_vcpu *vcpu,u64 data, -bool host_initiated) +bool vmx_is_valid_debugctl (struct kvm_vcpu *vcpu,u64 data,bool host_initiated) {u64 invalid;
arch/x86/kvm/vmx/vmx.h +3 -0
@@ -435,6 +435,9 @@ static inline void vmx_set_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr,void vmx_update_cpu_dirty_logging (struct kvm_vcpu *vcpu); +u64 vmx_get_supported_debugctl (struct kvm_vcpu *vcpu,bool host_initiated); +bool vmx_is_valid_debugctl (struct kvm_vcpu *vcpu,u64 data,bool host_initiated); +/* * Note, early Intel manuals have the write-low and read-high bitmap offsets * the wrong way round. The bitmaps control MSRs 0x00000000-0x00001fff and
Signature · 1 line
2.39.5