From: Amirmohammad Eftekhar <amirmohammad.eftekhar@cispa.de>
To: <seanjc@google.com>, <pbonzini@redhat.com>
Cc: <kvm@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
<amirmohammad.eftekhar@cispa.de>
Subject: [PATCH] KVM: nVMX: Restore L2's DEBUGCTL/BNDCFGS/CET from vmcs12 on RSM and nested state restore
Date: Fri, 23 Oct 2026 00:38:20 +0200 [thread overview]
Message-ID: <20261022223820.8279-1-amirmohammad.eftekhar@cispa.de> (raw)
nested_vmx_enter_non_root_mode() snapshots the guest's DEBUGCTL, BNDCFGS
and CET state (S_CET/SSP/SSP_TBL) into vmx->nested.pre_vmenter_* so that
prepare_vmcs02() can preserve into vmcs02 any of those fields that VM
entry leaves unchanged, i.e. whose VM_ENTRY_LOAD_* control is clear. The
snapshot reads the currently loaded VMCS.
That is correct for VMLAUNCH/VMRESUME: the active VMCS is vmcs01, and
when VM entry does not load a field L2 does inherit L1's value for it.
It is wrong for the two from_vmentry == false callers -- RSM back into L2
(vmx_leave_smm()) and KVM_SET_NESTED_STATE -- because there the active
VMCS is still vmcs01, holding L1's live state, while the state L2 must
resume with lives in vmcs12. On RSM the pre-SMI values were put in
vmcs12 when the SMI forced the L2 -> L1 exit (CET via
sync_vmcs02_to_vmcs12(), DEBUGCTL/BNDCFGS tracked in vmcs12 as L2 updates
them); on nested state restore vmcs12 is the state userspace supplied.
So after an SMI taken while L2 is running, followed by RSM -- a sequence
entirely under the guest's control -- or after a restore, L2 resumes with
L1's DEBUGCTL, BNDCFGS and CET instead of its own whenever L1 left the
corresponding VM_ENTRY_LOAD_* control clear. Nothing rejects it: the
physical VM entry sees a legal vmcs02 (the stale values are valid, just
not L2's), so the state is silently wrong rather than faulted.
Source the snapshot from vmcs12 on the !from_vmentry paths.
Signed-off-by: Amirmohammad Eftekhar <amirmohammad.eftekhar@cispa.de>
---
Notes (not for the commit message):
- Fidelity/correctness bug: the victim is L2 and the entity that both
owns L1 and drove the SMI is L1, so this is L1 corrupting its own L2,
not a privilege-boundary crossing -- not memory-safety and not
guest -> host. It is a concrete instance of the existing in-tree
"L2's values may be corrupted on SMI+RSM" TODO near vmx_enter_smm().
- The same snapshot bug applies to the KVM_SET_NESTED_STATE restore
path, which this fixes too.
- DEBUGCTL/BNDCFGS have read the active VMCS here for a long time; the
CET arm is newer. Happy to add whatever Fixes:/Cc: stable scope you
prefer rather than guess the split.
- Verified against mainline (v7.3-rc6) and kvm-x86/next; please confirm
it still applies on your tree, I will rebase if needed.
arch/x86/kvm/vmx/nested.c | 31 +++++++++++++++++++++++++------
1 file changed, 25 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 151873407ab..c51dcb1cb8d 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -3650,19 +3650,38 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
kvm_service_local_tlb_flush_requests(vcpu);
+ /*
+ * Snapshot the state that VM-Enter leaves unchanged when the matching
+ * VM_ENTRY_LOAD_* control is clear, so it can be restored into vmcs02.
+ * On VM-Enter the active VMCS is vmcs01 and its guest state is what L2
+ * inherits. On the !from_vmentry paths (RSM back into L2, and
+ * KVM_SET_NESTED_STATE) the active VMCS is still vmcs01, i.e. holds
+ * L1's state, whereas L2's state lives in vmcs12 -- read it from there
+ * so that resuming L2 doesn't clobber its DEBUGCTL/BNDCFGS/CET with
+ * L1's values.
+ */
if (!vcpu->arch.nested_run_pending ||
!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
- vmx->nested.pre_vmenter_debugctl = vmx_guest_debugctl_read();
+ vmx->nested.pre_vmenter_debugctl = from_vmentry ?
+ vmx_guest_debugctl_read() : vmcs12->guest_ia32_debugctl;
if (kvm_mpx_supported() &&
(!vcpu->arch.nested_run_pending ||
!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS)))
- vmx->nested.pre_vmenter_bndcfgs = vmcs_read64(GUEST_BNDCFGS);
+ vmx->nested.pre_vmenter_bndcfgs = from_vmentry ?
+ vmcs_read64(GUEST_BNDCFGS) : vmcs12->guest_bndcfgs;
if (!vcpu->arch.nested_run_pending ||
- !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_CET_STATE))
- vmcs_read_cet_state(vcpu, &vmx->nested.pre_vmenter_s_cet,
- &vmx->nested.pre_vmenter_ssp,
- &vmx->nested.pre_vmenter_ssp_tbl);
+ !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_CET_STATE)) {
+ if (from_vmentry) {
+ vmcs_read_cet_state(vcpu, &vmx->nested.pre_vmenter_s_cet,
+ &vmx->nested.pre_vmenter_ssp,
+ &vmx->nested.pre_vmenter_ssp_tbl);
+ } else {
+ vmx->nested.pre_vmenter_s_cet = vmcs12->guest_s_cet;
+ vmx->nested.pre_vmenter_ssp = vmcs12->guest_ssp;
+ vmx->nested.pre_vmenter_ssp_tbl = vmcs12->guest_ssp_tbl;
+ }
+ }
/*
* Stash L1's CR3, so that in the event of a "late" VM-Fail, i.e. a
--
2.54.0
next reply other threads:[~2026-10-22 22:38 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-22 22:38 Amirmohammad Eftekhar [this message]
2026-10-23 9:03 ` Amirmohammad Eftekhar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261022223820.8279-1-amirmohammad.eftekhar@cispa.de \
--to=amirmohammad.eftekhar@cispa.de \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®