Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

KVM: SEV: Disallow LAUNCH_FINISH if vCPUs are actively being created

Reject LAUNCH_FINISH for SEV-ES and SNP VMs if KVM is actively creating
one or more vCPUs, as KVM needs to process and encrypt each vCPU's VMSA.
Letting userspace create vCPUs while LAUNCH_FINISH is in-progress is
"fine", at least in the current code base, as kvm_for_each_vcpu() operates
on online_vcpus, LAUNCH_FINISH (all SEV+ sub-ioctls) holds kvm->mutex, and
fully onlining a vCPU in kvm_vm_ioctl_create_vcpu() is done under
kvm->mutex. I.e. there's no difference between an in-progress vCPU and a
vCPU that is created entirely after LAUNCH_FINISH.

However, given that concurrent LAUNCH_FINISH and vCPU creation can't
possibly work (for any reasonable definition of "work"), since userspace
can't guarantee whether a particular vCPU will be encrypted or not,
disallow the combination as a hardening measure, to reduce the probability
of introducing bugs in the future, and to avoid having to reason about the
safety of future changes related to LAUNCH_FINISH.

Cc: Jethro Beekman <jethro@fortanix.com>
Closes: https://lore.kernel.org/all/b31f7c6e-2807-4662-bcdd-eea2c1e132fa@fortanix.com
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260310234829.2608037-5-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>

+15 -2
+8 -2
arch/x86/kvm/svm/sev.c
··· 1032 1032 if (!sev_es_guest(kvm)) 1033 1033 return -ENOTTY; 1034 1034 1035 + if (kvm_is_vcpu_creation_in_progress(kvm)) 1036 + return -EBUSY; 1037 + 1035 1038 kvm_for_each_vcpu(i, vcpu, kvm) { 1036 1039 ret = mutex_lock_killable(&vcpu->mutex); 1037 1040 if (ret) ··· 2055 2052 struct kvm_vcpu *src_vcpu; 2056 2053 unsigned long i; 2057 2054 2058 - if (src->created_vcpus != atomic_read(&src->online_vcpus) || 2059 - dst->created_vcpus != atomic_read(&dst->online_vcpus)) 2055 + if (kvm_is_vcpu_creation_in_progress(src) || 2056 + kvm_is_vcpu_creation_in_progress(dst)) 2060 2057 return -EBUSY; 2061 2058 2062 2059 if (!sev_es_guest(src)) ··· 2454 2451 struct kvm_vcpu *vcpu; 2455 2452 unsigned long i; 2456 2453 int ret; 2454 + 2455 + if (kvm_is_vcpu_creation_in_progress(kvm)) 2456 + return -EBUSY; 2457 2457 2458 2458 data.gctx_paddr = __psp_pa(sev->snp_context); 2459 2459 data.page_type = SNP_PAGE_TYPE_VMSA;
+7
include/linux/kvm_host.h
··· 1029 1029 return NULL; 1030 1030 } 1031 1031 1032 + static inline bool kvm_is_vcpu_creation_in_progress(struct kvm *kvm) 1033 + { 1034 + lockdep_assert_held(&kvm->lock); 1035 + 1036 + return kvm->created_vcpus != atomic_read(&kvm->online_vcpus); 1037 + } 1038 + 1032 1039 void kvm_destroy_vcpus(struct kvm *kvm); 1033 1040 1034 1041 int kvm_trylock_all_vcpus(struct kvm *kvm);