]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.16-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 18 Aug 2025 11:22:34 +0000 (13:22 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 18 Aug 2025 11:22:34 +0000 (13:22 +0200)
added patches:
kvm-nvmx-check-vmcs12-guest_ia32_debugctl-on-nested-vm-enter.patch
kvm-vmx-extract-checking-of-guest-s-debugctl-into-helper.patch
kvm-vmx-preserve-host-s-debugctlmsr_freeze_in_smm-while-running-the-guest.patch
kvm-vmx-wrap-all-accesses-to-ia32_debugctl-with-getter-setter-apis.patch

queue-6.16/kvm-nvmx-check-vmcs12-guest_ia32_debugctl-on-nested-vm-enter.patch [new file with mode: 0644]
queue-6.16/kvm-vmx-extract-checking-of-guest-s-debugctl-into-helper.patch [new file with mode: 0644]
queue-6.16/kvm-vmx-preserve-host-s-debugctlmsr_freeze_in_smm-while-running-the-guest.patch [new file with mode: 0644]
queue-6.16/kvm-vmx-wrap-all-accesses-to-ia32_debugctl-with-getter-setter-apis.patch [new file with mode: 0644]
queue-6.16/series

diff --git a/queue-6.16/kvm-nvmx-check-vmcs12-guest_ia32_debugctl-on-nested-vm-enter.patch b/queue-6.16/kvm-nvmx-check-vmcs12-guest_ia32_debugctl-on-nested-vm-enter.patch
new file mode 100644 (file)
index 0000000..6a030b7
--- /dev/null
@@ -0,0 +1,111 @@
+From stable+bounces-169594-greg=kroah.com@vger.kernel.org Thu Aug 14 18:14:37 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Aug 2025 12:12:10 -0400
+Subject: KVM: nVMX: Check vmcs12->guest_ia32_debugctl on nested VM-Enter
+To: stable@vger.kernel.org
+Cc: Maxim Levitsky <mlevitsk@redhat.com>, Sean Christopherson <seanjc@google.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20250814161212.2107674-4-sashal@kernel.org>
+
+From: Maxim Levitsky <mlevitsk@redhat.com>
+
+[ 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.
+
+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
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Stable-dep-of: 6b1dd26544d0 ("KVM: VMX: Preserve host's DEBUGCTLMSR_FREEZE_IN_SMM while running the guest")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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(-)
+
+--- a/arch/x86/kvm/vmx/nested.c
++++ b/arch/x86/kvm/vmx/nested.c
+@@ -2663,7 +2663,8 @@ static int prepare_vmcs02(struct kvm_vcp
+       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(
+               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
+               (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;
+--- a/arch/x86/kvm/vmx/vmx.c
++++ b/arch/x86/kvm/vmx/vmx.c
+@@ -2174,7 +2174,7 @@ static u64 nested_vmx_truncate_sysenter_
+       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(st
+       return 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;
+--- a/arch/x86/kvm/vmx/vmx.h
++++ b/arch/x86/kvm/vmx/vmx.h
+@@ -414,6 +414,9 @@ static inline void vmx_set_intercept_for
+ 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
diff --git a/queue-6.16/kvm-vmx-extract-checking-of-guest-s-debugctl-into-helper.patch b/queue-6.16/kvm-vmx-extract-checking-of-guest-s-debugctl-into-helper.patch
new file mode 100644 (file)
index 0000000..c99e1f2
--- /dev/null
@@ -0,0 +1,88 @@
+From stable+bounces-169593-greg=kroah.com@vger.kernel.org Thu Aug 14 18:17:45 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Aug 2025 12:12:09 -0400
+Subject: KVM: VMX: Extract checking of guest's DEBUGCTL into helper
+To: stable@vger.kernel.org
+Cc: Sean Christopherson <seanjc@google.com>, Dapeng Mi <dapeng1.mi@linux.intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20250814161212.2107674-3-sashal@kernel.org>
+
+From: Sean Christopherson <seanjc@google.com>
+
+[ 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.
+
+Reviewed-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
+Link: https://lore.kernel.org/r/20250610232010.162191-6-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Stable-dep-of: 6b1dd26544d0 ("KVM: VMX: Preserve host's DEBUGCTLMSR_FREEZE_IN_SMM while running the guest")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/vmx/vmx.c |   29 +++++++++++++++++------------
+ 1 file changed, 17 insertions(+), 12 deletions(-)
+
+--- a/arch/x86/kvm/vmx/vmx.c
++++ b/arch/x86/kvm/vmx/vmx.c
+@@ -2193,6 +2193,19 @@ static u64 vmx_get_supported_debugctl(st
+       return 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.
+@@ -2261,19 +2274,12 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, s
+               }
+               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;
+@@ -2283,7 +2289,6 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, s
+                   (data & DEBUGCTLMSR_LBR))
+                       intel_pmu_create_guest_lbr_event(vcpu);
+               return 0;
+-      }
+       case MSR_IA32_BNDCFGS:
+               if (!kvm_mpx_supported() ||
+                   (!msr_info->host_initiated &&
diff --git a/queue-6.16/kvm-vmx-preserve-host-s-debugctlmsr_freeze_in_smm-while-running-the-guest.patch b/queue-6.16/kvm-vmx-preserve-host-s-debugctlmsr_freeze_in_smm-while-running-the-guest.patch
new file mode 100644 (file)
index 0000000..c17099a
--- /dev/null
@@ -0,0 +1,182 @@
+From stable+bounces-169596-greg=kroah.com@vger.kernel.org Thu Aug 14 18:14:39 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Aug 2025 12:12:12 -0400
+Subject: KVM: VMX: Preserve host's DEBUGCTLMSR_FREEZE_IN_SMM while running the guest
+To: stable@vger.kernel.org
+Cc: Maxim Levitsky <mlevitsk@redhat.com>, Sean Christopherson <seanjc@google.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20250814161212.2107674-6-sashal@kernel.org>
+
+From: Maxim Levitsky <mlevitsk@redhat.com>
+
+[ Upstream commit 6b1dd26544d045f6a79e8c73572c0c0db3ef3c1a ]
+
+Set/clear DEBUGCTLMSR_FREEZE_IN_SMM in GUEST_IA32_DEBUGCTL based on the
+host's pre-VM-Enter value, i.e. preserve the host's FREEZE_IN_SMM setting
+while running the guest.  When running with the "default treatment of SMIs"
+in effect (the only mode KVM supports), SMIs do not generate a VM-Exit that
+is visible to host (non-SMM) software, and instead transitions directly
+from VMX non-root to SMM.  And critically, DEBUGCTL isn't context switched
+by hardware on SMI or RSM, i.e. SMM will run with whatever value was
+resident in hardware at the time of the SMI.
+
+Failure to preserve FREEZE_IN_SMM results in the PMU unexpectedly counting
+events while the CPU is executing in SMM, which can pollute profiling and
+potentially leak information into the guest.
+
+Check for changes in FREEZE_IN_SMM prior to every entry into KVM's inner
+run loop, as the bit can be toggled in IRQ context via IPI callback (SMP
+function call), by way of /sys/devices/cpu/freeze_on_smi.
+
+Add a field in kvm_x86_ops to communicate which DEBUGCTL bits need to be
+preserved, as FREEZE_IN_SMM is only supported and defined for Intel CPUs,
+i.e. explicitly checking FREEZE_IN_SMM in common x86 is at best weird, and
+at worst could lead to undesirable behavior in the future if AMD CPUs ever
+happened to pick up a collision with the bit.
+
+Exempt TDX vCPUs, i.e. protected guests, from the check, as the TDX Module
+owns and controls GUEST_IA32_DEBUGCTL.
+
+WARN in SVM if KVM_RUN_LOAD_DEBUGCTL is set, mostly to document that the
+lack of handling isn't a KVM bug (TDX already WARNs on any run_flag).
+
+Lastly, explicitly reload GUEST_IA32_DEBUGCTL on a VM-Fail that is missed
+by KVM but detected by hardware, i.e. in nested_vmx_restore_host_state().
+Doing so avoids the need to track host_debugctl on a per-VMCS basis, as
+GUEST_IA32_DEBUGCTL is unconditionally written by prepare_vmcs02() and
+load_vmcs12_host_state().  For the VM-Fail case, even though KVM won't
+have actually entered the guest, vcpu_enter_guest() will have run with
+vmcs02 active and thus could result in vmcs01 being run with a stale value.
+
+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-9-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/include/asm/kvm_host.h |    7 +++++++
+ arch/x86/kvm/vmx/main.c         |    2 ++
+ arch/x86/kvm/vmx/nested.c       |    3 +++
+ arch/x86/kvm/vmx/vmx.c          |    3 +++
+ arch/x86/kvm/vmx/vmx.h          |   15 ++++++++++++++-
+ arch/x86/kvm/x86.c              |   14 ++++++++++++--
+ 6 files changed, 41 insertions(+), 3 deletions(-)
+
+--- a/arch/x86/include/asm/kvm_host.h
++++ b/arch/x86/include/asm/kvm_host.h
+@@ -1683,6 +1683,7 @@ static inline u16 kvm_lapic_irq_dest_mod
+ enum kvm_x86_run_flags {
+       KVM_RUN_FORCE_IMMEDIATE_EXIT    = BIT(0),
+       KVM_RUN_LOAD_GUEST_DR6          = BIT(1),
++      KVM_RUN_LOAD_DEBUGCTL           = BIT(2),
+ };
+ struct kvm_x86_ops {
+@@ -1713,6 +1714,12 @@ struct kvm_x86_ops {
+       void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu);
+       void (*vcpu_put)(struct kvm_vcpu *vcpu);
++      /*
++       * Mask of DEBUGCTL bits that are owned by the host, i.e. that need to
++       * match the host's value even while the guest is active.
++       */
++      const u64 HOST_OWNED_DEBUGCTL;
++
+       void (*update_exception_bitmap)(struct kvm_vcpu *vcpu);
+       int (*get_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr);
+       int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr);
+--- a/arch/x86/kvm/vmx/main.c
++++ b/arch/x86/kvm/vmx/main.c
+@@ -915,6 +915,8 @@ struct kvm_x86_ops vt_x86_ops __initdata
+       .vcpu_load = vt_op(vcpu_load),
+       .vcpu_put = vt_op(vcpu_put),
++      .HOST_OWNED_DEBUGCTL = DEBUGCTLMSR_FREEZE_IN_SMM,
++
+       .update_exception_bitmap = vt_op(update_exception_bitmap),
+       .get_feature_msr = vmx_get_feature_msr,
+       .get_msr = vt_op(get_msr),
+--- a/arch/x86/kvm/vmx/nested.c
++++ b/arch/x86/kvm/vmx/nested.c
+@@ -4861,6 +4861,9 @@ static void nested_vmx_restore_host_stat
+                       WARN_ON(kvm_set_dr(vcpu, 7, vmcs_readl(GUEST_DR7)));
+       }
++      /* Reload DEBUGCTL to ensure vmcs01 has a fresh FREEZE_IN_SMM value. */
++      vmx_reload_guest_debugctl(vcpu);
++
+       /*
+        * Note that calling vmx_set_{efer,cr0,cr4} is important as they
+        * handle a variety of side effects to KVM's software model.
+--- a/arch/x86/kvm/vmx/vmx.c
++++ b/arch/x86/kvm/vmx/vmx.c
+@@ -7377,6 +7377,9 @@ fastpath_t vmx_vcpu_run(struct kvm_vcpu
+       if (run_flags & KVM_RUN_LOAD_GUEST_DR6)
+               set_debugreg(vcpu->arch.dr6, 6);
++      if (run_flags & KVM_RUN_LOAD_DEBUGCTL)
++              vmx_reload_guest_debugctl(vcpu);
++
+       /*
+        * Refresh vmcs.HOST_CR3 if necessary.  This must be done immediately
+        * prior to VM-Enter, as the kernel may load a new ASID (PCID) any time
+--- a/arch/x86/kvm/vmx/vmx.h
++++ b/arch/x86/kvm/vmx/vmx.h
+@@ -419,12 +419,25 @@ bool vmx_is_valid_debugctl(struct kvm_vc
+ static inline void vmx_guest_debugctl_write(struct kvm_vcpu *vcpu, u64 val)
+ {
++      WARN_ON_ONCE(val & DEBUGCTLMSR_FREEZE_IN_SMM);
++
++      val |= vcpu->arch.host_debugctl & DEBUGCTLMSR_FREEZE_IN_SMM;
+       vmcs_write64(GUEST_IA32_DEBUGCTL, val);
+ }
+ static inline u64 vmx_guest_debugctl_read(void)
+ {
+-      return vmcs_read64(GUEST_IA32_DEBUGCTL);
++      return vmcs_read64(GUEST_IA32_DEBUGCTL) & ~DEBUGCTLMSR_FREEZE_IN_SMM;
++}
++
++static inline void vmx_reload_guest_debugctl(struct kvm_vcpu *vcpu)
++{
++      u64 val = vmcs_read64(GUEST_IA32_DEBUGCTL);
++
++      if (!((val ^ vcpu->arch.host_debugctl) & DEBUGCTLMSR_FREEZE_IN_SMM))
++              return;
++
++      vmx_guest_debugctl_write(vcpu, val & ~DEBUGCTLMSR_FREEZE_IN_SMM);
+ }
+ /*
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -10785,7 +10785,7 @@ static int vcpu_enter_guest(struct kvm_v
+               dm_request_for_irq_injection(vcpu) &&
+               kvm_cpu_accept_dm_intr(vcpu);
+       fastpath_t exit_fastpath;
+-      u64 run_flags;
++      u64 run_flags, debug_ctl;
+       bool req_immediate_exit = false;
+@@ -11057,7 +11057,17 @@ static int vcpu_enter_guest(struct kvm_v
+               set_debugreg(DR7_FIXED_1, 7);
+       }
+-      vcpu->arch.host_debugctl = get_debugctlmsr();
++      /*
++       * Refresh the host DEBUGCTL snapshot after disabling IRQs, as DEBUGCTL
++       * can be modified in IRQ context, e.g. via SMP function calls.  Inform
++       * vendor code if any host-owned bits were changed, e.g. so that the
++       * value loaded into hardware while running the guest can be updated.
++       */
++      debug_ctl = get_debugctlmsr();
++      if ((debug_ctl ^ vcpu->arch.host_debugctl) & kvm_x86_ops.HOST_OWNED_DEBUGCTL &&
++          !vcpu->arch.guest_state_protected)
++              run_flags |= KVM_RUN_LOAD_DEBUGCTL;
++      vcpu->arch.host_debugctl = debug_ctl;
+       guest_timing_enter_irqoff();
diff --git a/queue-6.16/kvm-vmx-wrap-all-accesses-to-ia32_debugctl-with-getter-setter-apis.patch b/queue-6.16/kvm-vmx-wrap-all-accesses-to-ia32_debugctl-with-getter-setter-apis.patch
new file mode 100644 (file)
index 0000000..6375f22
--- /dev/null
@@ -0,0 +1,155 @@
+From stable+bounces-169595-greg=kroah.com@vger.kernel.org Thu Aug 14 18:14:39 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Aug 2025 12:12:11 -0400
+Subject: KVM: VMX: Wrap all accesses to IA32_DEBUGCTL with getter/setter APIs
+To: stable@vger.kernel.org
+Cc: Maxim Levitsky <mlevitsk@redhat.com>, Dapeng Mi <dapeng1.mi@linux.intel.com>, Sean Christopherson <seanjc@google.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20250814161212.2107674-5-sashal@kernel.org>
+
+From: Maxim Levitsky <mlevitsk@redhat.com>
+
+[ Upstream commit 7d0cce6cbe71af6e9c1831bff101a2b9c249c4a2 ]
+
+Introduce vmx_guest_debugctl_{read,write}() to handle all accesses to
+vmcs.GUEST_IA32_DEBUGCTL. This will allow stuffing FREEZE_IN_SMM into
+GUEST_IA32_DEBUGCTL based on the host setting without bleeding the state
+into the guest, and without needing to copy+paste the FREEZE_IN_SMM
+logic into every patch that accesses GUEST_IA32_DEBUGCTL.
+
+No functional change intended.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
+[sean: massage changelog, make inline, use in all prepare_vmcs02() cases]
+Reviewed-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
+Link: https://lore.kernel.org/r/20250610232010.162191-8-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Stable-dep-of: 6b1dd26544d0 ("KVM: VMX: Preserve host's DEBUGCTLMSR_FREEZE_IN_SMM while running the guest")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/vmx/nested.c    |   10 +++++-----
+ arch/x86/kvm/vmx/pmu_intel.c |    8 ++++----
+ arch/x86/kvm/vmx/vmx.c       |    8 +++++---
+ arch/x86/kvm/vmx/vmx.h       |   10 ++++++++++
+ 4 files changed, 24 insertions(+), 12 deletions(-)
+
+--- a/arch/x86/kvm/vmx/nested.c
++++ b/arch/x86/kvm/vmx/nested.c
+@@ -2663,11 +2663,11 @@ static int prepare_vmcs02(struct kvm_vcp
+       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 &
+-                                                vmx_get_supported_debugctl(vcpu, false));
++              vmx_guest_debugctl_write(vcpu, 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);
++              vmx_guest_debugctl_write(vcpu, vmx->nested.pre_vmenter_debugctl);
+       }
+       if (kvm_mpx_supported() && (!vmx->nested.nested_run_pending ||
+           !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS)))
+@@ -3532,7 +3532,7 @@ enum nvmx_vmentry_status nested_vmx_ente
+       if (!vmx->nested.nested_run_pending ||
+           !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
+-              vmx->nested.pre_vmenter_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
++              vmx->nested.pre_vmenter_debugctl = vmx_guest_debugctl_read();
+       if (kvm_mpx_supported() &&
+           (!vmx->nested.nested_run_pending ||
+            !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS)))
+@@ -4806,7 +4806,7 @@ static void load_vmcs12_host_state(struc
+       __vmx_set_segment(vcpu, &seg, VCPU_SREG_LDTR);
+       kvm_set_dr(vcpu, 7, 0x400);
+-      vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
++      vmx_guest_debugctl_write(vcpu, 0);
+       if (nested_vmx_load_msr(vcpu, vmcs12->vm_exit_msr_load_addr,
+                               vmcs12->vm_exit_msr_load_count))
+--- a/arch/x86/kvm/vmx/pmu_intel.c
++++ b/arch/x86/kvm/vmx/pmu_intel.c
+@@ -653,11 +653,11 @@ static void intel_pmu_reset(struct kvm_v
+  */
+ static void intel_pmu_legacy_freezing_lbrs_on_pmi(struct kvm_vcpu *vcpu)
+ {
+-      u64 data = vmcs_read64(GUEST_IA32_DEBUGCTL);
++      u64 data = vmx_guest_debugctl_read();
+       if (data & DEBUGCTLMSR_FREEZE_LBRS_ON_PMI) {
+               data &= ~DEBUGCTLMSR_LBR;
+-              vmcs_write64(GUEST_IA32_DEBUGCTL, data);
++              vmx_guest_debugctl_write(vcpu, data);
+       }
+ }
+@@ -730,7 +730,7 @@ void vmx_passthrough_lbr_msrs(struct kvm
+       if (!lbr_desc->event) {
+               vmx_disable_lbr_msrs_passthrough(vcpu);
+-              if (vmcs_read64(GUEST_IA32_DEBUGCTL) & DEBUGCTLMSR_LBR)
++              if (vmx_guest_debugctl_read() & DEBUGCTLMSR_LBR)
+                       goto warn;
+               if (test_bit(INTEL_PMC_IDX_FIXED_VLBR, pmu->pmc_in_use))
+                       goto warn;
+@@ -752,7 +752,7 @@ warn:
+ static void intel_pmu_cleanup(struct kvm_vcpu *vcpu)
+ {
+-      if (!(vmcs_read64(GUEST_IA32_DEBUGCTL) & DEBUGCTLMSR_LBR))
++      if (!(vmx_guest_debugctl_read() & DEBUGCTLMSR_LBR))
+               intel_pmu_release_guest_lbr_event(vcpu);
+ }
+--- a/arch/x86/kvm/vmx/vmx.c
++++ b/arch/x86/kvm/vmx/vmx.c
+@@ -2149,7 +2149,7 @@ int vmx_get_msr(struct kvm_vcpu *vcpu, s
+                       msr_info->data = vmx->pt_desc.guest.addr_a[index / 2];
+               break;
+       case MSR_IA32_DEBUGCTLMSR:
+-              msr_info->data = vmcs_read64(GUEST_IA32_DEBUGCTL);
++              msr_info->data = vmx_guest_debugctl_read();
+               break;
+       default:
+       find_uret_msr:
+@@ -2283,7 +2283,8 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, s
+                                               VM_EXIT_SAVE_DEBUG_CONTROLS)
+                       get_vmcs12(vcpu)->guest_ia32_debugctl = data;
+-              vmcs_write64(GUEST_IA32_DEBUGCTL, data);
++              vmx_guest_debugctl_write(vcpu, data);
++
+               if (intel_pmu_lbr_is_enabled(vcpu) && !to_vmx(vcpu)->lbr_desc.event &&
+                   (data & DEBUGCTLMSR_LBR))
+                       intel_pmu_create_guest_lbr_event(vcpu);
+@@ -4798,7 +4799,8 @@ static void init_vmcs(struct vcpu_vmx *v
+       vmcs_write32(GUEST_SYSENTER_CS, 0);
+       vmcs_writel(GUEST_SYSENTER_ESP, 0);
+       vmcs_writel(GUEST_SYSENTER_EIP, 0);
+-      vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
++
++      vmx_guest_debugctl_write(&vmx->vcpu, 0);
+       if (cpu_has_vmx_tpr_shadow()) {
+               vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0);
+--- a/arch/x86/kvm/vmx/vmx.h
++++ b/arch/x86/kvm/vmx/vmx.h
+@@ -417,6 +417,16 @@ void vmx_update_cpu_dirty_logging(struct
+ 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);
++static inline void vmx_guest_debugctl_write(struct kvm_vcpu *vcpu, u64 val)
++{
++      vmcs_write64(GUEST_IA32_DEBUGCTL, val);
++}
++
++static inline u64 vmx_guest_debugctl_read(void)
++{
++      return vmcs_read64(GUEST_IA32_DEBUGCTL);
++}
++
+ /*
+  * Note, early Intel manuals have the write-low and read-high bitmap offsets
+  * the wrong way round.  The bitmaps control MSRs 0x00000000-0x00001fff and
index 3586bf6df927aca34201e257ee7bb3f881fe9e36..10cacd4029798c1fe652c1f2d6f40f3ecaff39cb 100644 (file)
@@ -554,3 +554,7 @@ media-i2c-vd55g1-fix-return-code-in-vd55g1_enable_streams-error-path.patch
 tracing-fprobe-fix-infinite-recursion-using-preempt_-_notrace.patch
 tools-nolibc-fix-spelling-of-fd_setbitmask-in-fd_-macros.patch
 rdma-siw-fix-the-sendmsg-byte-count-in-siw_tcp_sendpages.patch
+kvm-vmx-extract-checking-of-guest-s-debugctl-into-helper.patch
+kvm-nvmx-check-vmcs12-guest_ia32_debugctl-on-nested-vm-enter.patch
+kvm-vmx-wrap-all-accesses-to-ia32_debugctl-with-getter-setter-apis.patch
+kvm-vmx-preserve-host-s-debugctlmsr_freeze_in_smm-while-running-the-guest.patch