Skip to content

Commit 72d1271

Browse files
committed
KVM: SVM: Refuse to attempt VRMUN if an SEV-ES+ guest has an invalid VMSA
Explicitly reject KVM_RUN with KVM_EXIT_FAIL_ENTRY if userspace "coerces" KVM into running an SEV-ES+ guest with an invalid VMSA, e.g. by modifying a vCPU's mp_state to be RUNNABLE after an SNP vCPU has undergone a Destroy event. On Destroy or failed Create, KVM marks the vCPU HALTED so that *KVM* doesn't run the vCPU, but nothing prevents a misbehaving VMM from manually making the vCPU RUNNABLE via KVM_SET_MP_STATE. Attempting VMRUN with an invalid VMSA should be harmless, but knowingly executing VMRUN with bad control state is at best dodgy. Fixes: e366f92 ("KVM: SEV: Support SEV-SNP AP Creation NAE event") Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com> Reviewed-by: Pankaj Gupta <pankaj.gupta@amd.com> Link: https://lore.kernel.org/r/20250227012541.3234589-4-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent d4b69c3 commit 72d1271

File tree

3 files changed

+23
-6
lines changed

3 files changed

+23
-6
lines changed

arch/x86/kvm/svm/sev.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3451,10 +3451,19 @@ void sev_es_unmap_ghcb(struct vcpu_svm *svm)
34513451
svm->sev_es.ghcb = NULL;
34523452
}
34533453

3454-
void pre_sev_run(struct vcpu_svm *svm, int cpu)
3454+
int pre_sev_run(struct vcpu_svm *svm, int cpu)
34553455
{
34563456
struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, cpu);
3457-
unsigned int asid = sev_get_asid(svm->vcpu.kvm);
3457+
struct kvm *kvm = svm->vcpu.kvm;
3458+
unsigned int asid = sev_get_asid(kvm);
3459+
3460+
/*
3461+
* Reject KVM_RUN if userspace attempts to run the vCPU with an invalid
3462+
* VMSA, e.g. if userspace forces the vCPU to be RUNNABLE after an SNP
3463+
* AP Destroy event.
3464+
*/
3465+
if (sev_es_guest(kvm) && !VALID_PAGE(svm->vmcb->control.vmsa_pa))
3466+
return -EINVAL;
34583467

34593468
/* Assign the asid allocated with this SEV guest */
34603469
svm->asid = asid;
@@ -3467,11 +3476,12 @@ void pre_sev_run(struct vcpu_svm *svm, int cpu)
34673476
*/
34683477
if (sd->sev_vmcbs[asid] == svm->vmcb &&
34693478
svm->vcpu.arch.last_vmentry_cpu == cpu)
3470-
return;
3479+
return 0;
34713480

34723481
sd->sev_vmcbs[asid] = svm->vmcb;
34733482
svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ASID;
34743483
vmcb_mark_dirty(svm->vmcb, VMCB_ASID);
3484+
return 0;
34753485
}
34763486

34773487
#define GHCB_SCRATCH_AREA_LIMIT (16ULL * PAGE_SIZE)

arch/x86/kvm/svm/svm.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3599,7 +3599,7 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
35993599
return svm_invoke_exit_handler(vcpu, exit_code);
36003600
}
36013601

3602-
static void pre_svm_run(struct kvm_vcpu *vcpu)
3602+
static int pre_svm_run(struct kvm_vcpu *vcpu)
36033603
{
36043604
struct svm_cpu_data *sd = per_cpu_ptr(&svm_data, vcpu->cpu);
36053605
struct vcpu_svm *svm = to_svm(vcpu);
@@ -3621,6 +3621,8 @@ static void pre_svm_run(struct kvm_vcpu *vcpu)
36213621
/* FIXME: handle wraparound of asid_generation */
36223622
if (svm->current_vmcb->asid_generation != sd->asid_generation)
36233623
new_asid(svm, sd);
3624+
3625+
return 0;
36243626
}
36253627

36263628
static void svm_inject_nmi(struct kvm_vcpu *vcpu)
@@ -4243,7 +4245,12 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu,
42434245
if (force_immediate_exit)
42444246
smp_send_reschedule(vcpu->cpu);
42454247

4246-
pre_svm_run(vcpu);
4248+
if (pre_svm_run(vcpu)) {
4249+
vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY;
4250+
vcpu->run->fail_entry.hardware_entry_failure_reason = SVM_EXIT_ERR;
4251+
vcpu->run->fail_entry.cpu = vcpu->cpu;
4252+
return EXIT_FASTPATH_EXIT_USERSPACE;
4253+
}
42474254

42484255
sync_lapic_to_cr8(vcpu);
42494256

arch/x86/kvm/svm/svm.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ void avic_refresh_virtual_apic_mode(struct kvm_vcpu *vcpu);
742742

743743
/* sev.c */
744744

745-
void pre_sev_run(struct vcpu_svm *svm, int cpu);
745+
int pre_sev_run(struct vcpu_svm *svm, int cpu);
746746
void sev_init_vmcb(struct vcpu_svm *svm);
747747
void sev_vcpu_after_set_cpuid(struct vcpu_svm *svm);
748748
int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in);

0 commit comments

Comments
 (0)