Re: [PATCH v2 1/2] KVM: SVM: Triple fault L1 on unintercepted EFER.SVME clear by L2

From: Yosry Ahmed

Date: Thu Feb 26 2026 - 12:39:48 EST


On Mon, Feb 09, 2026 at 07:51:41PM +0000, Yosry Ahmed wrote:
> KVM tracks when EFER.SVME is set and cleared to initialize and tear down
> nested state. However, it doesn't differentiate if EFER.SVME is getting
> toggled in L1 or L2+. If L2 clears EFER.SVME, and L1 does not intercept
> the EFER write, KVM exits guest mode and tears down nested state while
> L2 is running, executing L1 without injecting a proper #VMEXIT.
>
> According to the APM:
>
> The effect of turning off EFER.SVME while a guest is running is
> undefined; therefore, the VMM should always prevent guests from
> writing EFER.
>
> Since the behavior is architecturally undefined, KVM gets to choose what
> to do. Inject a triple fault into L1 as a more graceful option that
> running L1 with corrupted state.
>
> Co-developed-by: Sean Christopherson <seanjc@xxxxxxxxxx>
> Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx>
> Signed-off-by: Yosry Ahmed <yosry.ahmed@xxxxxxxxx>
> ---
> arch/x86/kvm/svm/svm.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 5f0136dbdde6..ccd73a3be3f9 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -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..


> svm_leave_nested(vcpu);
> /* #GP intercept is still needed for vmware backdoor */
> if (!enable_vmware_backdoor)
> --
> 2.53.0.rc2.204.g2597b5adb4-goog
>