From: Sean Christopherson Date: Mon, 14 Jul 2025 22:19:28 +0000 (-0700) Subject: KVM: VMX: Ensure unused kvm_tdx_capabilities fields are zeroed out X-Git-Tag: v6.16-rc7~23^2^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b8be70ec2b47ca62ccb54dc3c2ab9a9c93653e00;p=thirdparty%2Flinux.git KVM: VMX: Ensure unused kvm_tdx_capabilities fields are zeroed out Zero-allocate the kernel's kvm_tdx_capabilities structure and copy only the number of CPUID entries from the userspace structure. As is, KVM doesn't ensure kernel_tdvmcallinfo_1_{r11,r12} and user_tdvmcallinfo_1_r12 are zeroed, i.e. KVM will reflect whatever happens to be in the userspace structure back at userspace, and thus may report garbage to userspace. Zeroing the entire kernel structure also provides better semantics for the reserved field. E.g. if KVM extends kvm_tdx_capabilities to enumerate new information by repurposing bytes from the reserved field, userspace would be required to zero the new field in order to get useful information back (because older KVMs without support for the repurposed field would report garbage, a la the aforementioned tdvmcallinfo bugs). Fixes: 61bb28279623 ("KVM: TDX: Get system-wide info about TDX module on initialization") Suggested-by: Rick Edgecombe Reported-by: Xiaoyao Li Closes: https://lore.kernel.org/all/3ef581f1-1ff1-4b99-b216-b316f6415318@intel.com Tested-by: Xiaoyao Li Reviewed-by: Xiaoyao Li Reviewed-by: Rick Edgecombe Link: https://lore.kernel.org/r/20250714221928.1788095-1-seanjc@google.com Signed-off-by: Sean Christopherson --- diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index f31ccdeb905b..40d8c349c0e0 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -2271,25 +2271,26 @@ static int tdx_get_capabilities(struct kvm_tdx_cmd *cmd) const struct tdx_sys_info_td_conf *td_conf = &tdx_sysinfo->td_conf; struct kvm_tdx_capabilities __user *user_caps; struct kvm_tdx_capabilities *caps = NULL; + u32 nr_user_entries; int ret = 0; /* flags is reserved for future use */ if (cmd->flags) return -EINVAL; - caps = kmalloc(sizeof(*caps) + + caps = kzalloc(sizeof(*caps) + sizeof(struct kvm_cpuid_entry2) * td_conf->num_cpuid_config, GFP_KERNEL); if (!caps) return -ENOMEM; user_caps = u64_to_user_ptr(cmd->data); - if (copy_from_user(caps, user_caps, sizeof(*caps))) { + if (get_user(nr_user_entries, &user_caps->cpuid.nent)) { ret = -EFAULT; goto out; } - if (caps->cpuid.nent < td_conf->num_cpuid_config) { + if (nr_user_entries < td_conf->num_cpuid_config) { ret = -E2BIG; goto out; }