[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <5uwzlb3jvmebvienef5tw7cd6r4wgvtb5m5gu3wcaxh5sery3o@crh6m6cpuaqy>
Date: Tue, 6 Jan 2026 23:42:29 +0000
From: Yosry Ahmed <yosry.ahmed@...ux.dev>
To: Sean Christopherson <seanjc@...gle.com>
Cc: Kevin Cheng <chengkev@...gle.com>, pbonzini@...hat.com,
kvm@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH 1/2] KVM: SVM: Generate #UD for certain instructions when
SVME.EFER is disabled
On Tue, Jan 06, 2026 at 10:21:40AM -0800, Sean Christopherson wrote:
> On Tue, Jan 06, 2026, Kevin Cheng wrote:
> > The AMD APM states that VMRUN, VMLOAD, VMSAVE, CLGI, VMMCALL, and
> > INVLPGA instructions should generate a #UD when EFER.SVME is cleared.
> > Currently, when VMLOAD, VMSAVE, or CLGI are executed in L1 with
> > EFER.SVME cleared, no #UD is generated in certain cases. This is because
> > the intercepts for these instructions are cleared based on whether or
> > not vls or vgif is enabled. The #UD fails to be generated when the
> > intercepts are absent.
> >
> > INVLPGA is always intercepted, but there is no call to
> > nested_svm_check_permissions() which is responsible for checking
> > EFER.SVME and queuing the #UD exception.
>
> Please split the INVLPGA fix to a separate patch, it's very much a separate
> logical change. That will allow for more precise shortlogs, e.g.
>
> KVM: SVM: Recalc instructions intercepts when EFER.SVME is toggled
>
> and
>
> KVM: SVM: Inject #UD for INVLPGA if EFER.SVME=0
>
> > Fix the missing #UD generation by ensuring that all relevant
> > instructions have intercepts set when SVME.EFER is disabled and that the
> > exit handlers contain the necessary checks.
> >
> > VMMCALL is special because KVM's ABI is that VMCALL/VMMCALL are always
> > supported for L1 and never fault.
> >
> > Signed-off-by: Kevin Cheng <chengkev@...gle.com>
> > ---
> > arch/x86/kvm/svm/svm.c | 27 +++++++++++++++++++++++++--
> > 1 file changed, 25 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> > index 24d59ccfa40d9..fc1b8707bb00c 100644
> > --- a/arch/x86/kvm/svm/svm.c
> > +++ b/arch/x86/kvm/svm/svm.c
> > @@ -228,6 +228,14 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
> > if (!is_smm(vcpu))
> > svm_free_nested(svm);
> >
> > + /*
> > + * If EFER.SVME is being cleared, we must intercept these
>
> No pronouns.
>
> /*
> * Intercept instructions that #UD if EFER.SVME=0, as
> * SVME must be set even when running the guest, i.e.
> * hardware will only ever see EFER.SVME=1.
> */
>
> > + * instructions to ensure #UD is generated.
> > + */
> > + svm_set_intercept(svm, INTERCEPT_CLGI);
>
> What about STGI? Per the APM, it #UDs if:
>
> Secure Virtual Machine was not enabled (EFER.SVME=0) and both of the following
> conditions were true:
> • SVM Lock is not available, as indicated by CPUID Fn8000_000A_EDX[SVML] = 0.
> • DEV is not available, as indicated by CPUID Fn8000_0001_ECX[SKINIT] = 0.
>
>
> And this code in init_vmcb() can/should be dropped:
>
> if (vgif) {
> svm_clr_intercept(svm, INTERCEPT_STGI);
> svm_clr_intercept(svm, INTERCEPT_CLGI);
> svm->vmcb->control.int_ctl |= V_GIF_ENABLE_MASK;
> }
>
> > + svm_set_intercept(svm, INTERCEPT_VMSAVE);
> > + svm_set_intercept(svm, INTERCEPT_VMLOAD);
> > + svm->vmcb->control.virt_ext &= ~VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
> > } else {
> > int ret = svm_allocate_nested(svm);
> >
> > @@ -242,6 +250,15 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
> > */
> > if (svm_gp_erratum_intercept && !sev_guest(vcpu->kvm))
> > set_exception_intercept(svm, GP_VECTOR);
> > +
> > + if (vgif)
> > + svm_clr_intercept(svm, INTERCEPT_CLGI);
> > +
> > + if (vls) {
> > + svm_clr_intercept(svm, INTERCEPT_VMSAVE);
> > + svm_clr_intercept(svm, INTERCEPT_VMLOAD);
> > + svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
>
> This is wrong. In the rather absurd scenario that the vCPU model presented to
> the guest is an Intel CPU, KVM needs to intercept VMSAVE/VMLOAD to deal with the
> SYSENTER MSRs.
>
> This logic will also get blasted away if svm_recalc_instruction_intercepts()
> runs.
>
> So rather than manually handle the intercepts in svm_set_efer() and fight recalcs,
> trigger KVM_REQ_RECALC_INTERCEPTS and teach svm_recalc_instruction_intercepts()
> about EFER.SVME handling.
>
> After the dust settles, it might make sense to move the #GP intercept logic into
> svm_recalc_intercepts() as well, but that's not a priority.
Unrelated question about the #GP intercept logic, it seems like if
enable_vmware_backdoor is set, the #GP intercept will be set, even for
SEV guests, which goes against the in svm_set_efer():
/*
* Never intercept #GP for SEV guests, KVM can't
* decrypt guest memory to workaround the erratum.
*/
if (svm_gp_erratum_intercept && !sev_guest(vcpu->kvm))
set_exception_intercept(svm, GP_VECTOR);
I initially thought if userspace sets enable_vmware_backdoor and runs
SEV guests it's shooting itself in the foot, but given that
enable_vmware_backdoor is a module parameter (i.e. global), isn't it
possible that the host runs some SEV and some non-SEV VMs, where the
non-SEV VMs require the vmware backdoor?
Powered by blists - more mailing lists