From: Sean Christopherson <seanjc@google.com>
To: Yosry Ahmed <yosry@kernel.org>
Cc: Yosry Ahmed <yosry.ahmed@linux.dev>,
Paolo Bonzini <pbonzini@redhat.com>,
kvm@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 1/2] KVM: SVM: Triple fault L1 on unintercepted EFER.SVME clear by L2
Date: Fri, 27 Feb 2026 16:41:59 -0800 [thread overview]
Message-ID: <aaI51_1_bR4zRTXY@google.com> (raw)
In-Reply-To: <CAO9r8zOcBbgtNzy6FizPe8Xm8W=jg3CR8pmdByfszfEM3rqzsA@mail.gmail.com>
On Fri, Feb 27, 2026, Yosry Ahmed wrote:
> > > > @@ -216,6 +216,17 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
> > > >
> > > > if ((old_efer & EFER_SVME) != (efer & EFER_SVME)) {
> > > > if (!(efer & EFER_SVME)) {
> > > > + /*
> > > > + * Architecturally, clearing EFER.SVME while a guest is
> > > > + * running yields undefined behavior, i.e. KVM can do
> > > > + * literally anything. Force the vCPU back into L1 as
> > > > + * that is the safest option for KVM, but synthesize a
> > > > + * triple fault (for L1!) so that KVM at least doesn't
> > > > + * run random L2 code in the context of L1.
> > > > + */
> > > > + if (is_guest_mode(vcpu))
> > > > + kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
> > > > +
> > >
> > > Sigh, I think this is not correct in all cases:
> > >
> > > 1. If userspace restores a vCPU with EFER.SVME=0 to a vCPU with
> > > EFER.SVME=1 (e.g. restoring a vCPU running to a vCPU running L2).
> > > Typically KVM_SET_SREGS is done before KVM_SET_NESTED_STATE, so we may
> > > set EFER.SVME = 0 before leaving guest mode.
> > >
> > > 2. On vCPU reset, we clear EFER. Hmm, this one is seemingly okay tho,
> > > looking at kvm_vcpu_reset(), we leave nested first:
> > >
> > > /*
> > > * SVM doesn't unconditionally VM-Exit on INIT and SHUTDOWN, thus it's
> > > * possible to INIT the vCPU while L2 is active. Force the vCPU back
> > > * into L1 as EFER.SVME is cleared on INIT (along with all other EFER
> > > * bits), i.e. virtualization is disabled.
> > > */
> > > if (is_guest_mode(vcpu))
> > > kvm_leave_nested(vcpu);
> > >
> > > ...
> > >
> > > kvm_x86_call(set_efer)(vcpu, 0);
> > >
> > > So I think the only problematic case is (1). We can probably fix this by
> > > plumbing host_initiated through set_efer? This is getting more
> > > complicated than I would have liked..
> >
> > What if we instead hook WRMSR interception? A little fugly (well, more than a
> > little), but I think it would minimize the chances of a false-positive. The
> > biggest potential flaw I see is that this will incorrectly triple fault if KVM
> > synthesizes a #VMEXIT while emulating the WRMSR. But that really shouldn't
> > happen, because even a #GP=>#VMEXIT needs to be queued but not synthesized until
> > the emulation sequence completes (any other behavior would risk confusing KVM).
>
> What if we key off vcpu->wants_to_run?
That crossed my mind too.
> It's less protection against false positives from things like
> kvm_vcpu_reset() if it didn't leave nested before clearing EFER, but
> more protection against the #VMEXIT case you mentioned. Also should be
> much lower on the fugliness scale imo.
Yeah, I had pretty much the exact same thought process and assessment. I suggested
the WRMSR approach because I'm not sure how I feel about using wants_to_run for
functional behavior. But after realizing that hooking WRMSR won't handle RSM,
I'm solidly against my WRMSR idea.
Honestly, I'm leaning slightly towards dropping this patch entirely since it's
not a bug fix. But I'm definitely not completely against it either. So what if
we throw it in, but plan on reverting if there are any more problems (that aren't
obviously due to goofs elsewhere in KVM).
Is this what you were thinking?
---
arch/x86/kvm/svm/svm.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 1b31b033d79b..3e48e9c1c955 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -216,6 +216,19 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
if ((old_efer & EFER_SVME) != (efer & EFER_SVME)) {
if (!(efer & EFER_SVME)) {
+ /*
+ * Architecturally, clearing EFER.SVME while a guest is
+ * running yields undefined behavior, i.e. KVM can do
+ * literally anything. Force the vCPU back into L1 as
+ * that is the safest option for KVM, but synthesize a
+ * triple fault (for L1!) so that KVM at least doesn't
+ * run random L2 code in the context of L1. Do so if
+ * and only if the vCPU is actively running, e.g. to
+ * avoid positives if userspace is stuffing state.
+ */
+ if (is_guest_mode(vcpu) && vcpu->wants_to_run)
+ kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
+
svm_leave_nested(vcpu);
/* #GP intercept is still needed for vmware backdoor */
if (!enable_vmware_backdoor)
base-commit: 95deaec3557dced322e2540bfa426e60e5373d46
--
next prev parent reply other threads:[~2026-02-28 0:42 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-09 19:51 [PATCH v2 0/2] KVM: nSVM: Handle L2 clearing EFER.SVME properly Yosry Ahmed
2026-02-09 19:51 ` [PATCH v2 1/2] KVM: SVM: Triple fault L1 on unintercepted EFER.SVME clear by L2 Yosry Ahmed
2026-02-26 16:36 ` Yosry Ahmed
2026-02-26 18:20 ` Sean Christopherson
2026-02-27 20:03 ` Yosry Ahmed
2026-02-28 0:41 ` Sean Christopherson [this message]
2026-02-28 0:46 ` Yosry Ahmed
2026-03-02 22:48 ` Sean Christopherson
2026-02-09 19:51 ` [PATCH v2 2/2] KVM: selftests: Add a test for L2 clearing EFER.SVME without intercept Yosry Ahmed
2026-03-05 17:08 ` [PATCH v2 0/2] KVM: nSVM: Handle L2 clearing EFER.SVME properly Sean Christopherson
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=aaI51_1_bR4zRTXY@google.com \
--to=seanjc@google.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=yosry.ahmed@linux.dev \
--cc=yosry@kernel.org \
/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