From: Binbin Wu <binbin.wu@linux.intel.com>
To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org
Cc: seanjc@google.com, pbonzini@redhat.com,
dave.hansen@linux.intel.com, andrew.cooper3@citrix.com,
nik.borisov@suse.com, kas@kernel.org, rick.p.edgecombe@intel.com,
xiaoyao.li@intel.com, chao.gao@intel.com,
tony.lindgren@linux.intel.com, kishen.maloor@intel.com,
dedekind1@gmail.com, binbin.wu@linux.intel.com
Subject: [PATCH v6 4/4] KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM
Date: Wed, 28 Oct 2026 16:16:57 +0800 [thread overview]
Message-ID: <20261028081658.1228484-5-binbin.wu@linux.intel.com> (raw)
In-Reply-To: <20261028081658.1228484-1-binbin.wu@linux.intel.com>
Validate the CPUID configuration provided by userspace through
KVM_TDX_INIT_VM against KVM's TDX allowlist, and drop the hardcoded
denylist-based check.
The TDX module lets the VMM directly configure certain CPUID bits for a TD
at initialization time, but KVM must strictly govern which of those bits
userspace can set, otherwise a feature that clobbers host state could be
enabled behind KVM's back. The existing denylist rejects only TSX and
WAITPKG, and thus would accept any bit that a future TDX module makes
configurable, even if KVM knows nothing about the associated feature.
Rewrite tdx_is_unsupported_cpuid_entry() to reject KVM_TDX_INIT_VM if
userspace sets any bit outside of the mask returned by
tdx_get_cpuid_cfg_mask(), i.e. the same mask used to filter
KVM_TDX_CAPABILITIES. Don't bother intersecting the userspace input with
the bits that the TDX module reports as directly configurable, as the TDX
module itself rejects any bit outside that set.
Ignore the index for non-indexed functions when walking reverse_cpuid[],
as userspace isn't required to zero it.
Note, this is an ABI change, as KVM_TDX_INIT_VM now rejects some input
that was previously accepted. However, the semantics of KVM_TDX_INIT_VM
are unchanged: KVM already rejected unsupported CPUID bits, albeit via a
denylist, and userspace has always been required to consult
KVM_TDX_CAPABILITIES and set only the bits reported as configurable.
The change isn't expected to break userspace or guests:
- The newly rejected bits are no longer reported as configurable by
KVM_TDX_CAPABILITIES, so userspace that honors KVM_TDX_CAPABILITIES
won't set them.
- CORE_CAPABILITIES, which older TDX module specs defined as fixed-1, is
still allowed.
- The newly rejected features are either obsolete or unsupported by KVM,
and in the latter case, a guest relying on them would already have run
into problems.
Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Reviewed-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
---
v6:
- Rebased on patch series "x86/cpuid: KVM: TDX CPUID fixes"
https://lore.kernel.org/all/20261022210134.612848-1-seanjc@google.com
- Ignore the index for non-indexed functions when walking reverse_cpuid[].
- Fix the changelog on ABI change. (Rick)
- Collected RBs. (Rick, Chao, Xiaoyao)
v5:
- Update the changelog and call out the user-visible change more loudly.
(Rick)
- Drop the description in TDX document and the uapi header, as the ABI
itself is unchanged.
- Split the CPUID entry index check out to a separate fix patch.
v4:
- Update the comments/documentation.
- Collect RB tag from Tony.
v3:
- Check CPUID entry index mismatch b/t userspace input and TDX sysinfo
configuration. (Sashiko)
- No need to mask the userspace input with TDX module reported directly
configurable bits first, since the userspace input should be subset of
directly configurable bits. Otherwise, the input will be rejected by
the TDX module.
---
arch/x86/kvm/vmx/tdx.c | 41 ++++++++++++++++-------------------------
1 file changed, 16 insertions(+), 25 deletions(-)
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index 0741c3ef4745e..9b4e7db555347 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -276,29 +276,6 @@ static void __init tdx_initialize_cpu_cfg_caps(void)
#undef TDX_CFG_F
#undef TDX_CFG_INDEPENDENT_F
-#define TDX_FEATURE_TSX (__feature_bit(X86_FEATURE_HLE) | __feature_bit(X86_FEATURE_RTM))
-
-static bool has_tsx(const struct kvm_cpuid_entry2 *entry)
-{
- return entry->function == 7 && entry->index == 0 &&
- (entry->ebx & TDX_FEATURE_TSX);
-}
-
-static bool has_waitpkg(const struct kvm_cpuid_entry2 *entry)
-{
- return entry->function == 7 && entry->index == 0 &&
- (entry->ecx & __feature_bit(X86_FEATURE_WAITPKG));
-}
-
-static bool tdx_is_unsupported_cpuid_entry(const struct kvm_cpuid_entry2 *entry)
-{
- if (cpuid_function_is_indexed(entry->function) !=
- !!(entry->flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX))
- return true;
-
- return has_tsx(entry) || has_waitpkg(entry);
-}
-
#define TDX_CPUID_ALL_ALLOWED_MASK GENMASK_U32(31, 0)
static u32 tdx_get_cpuid_cfg_non_feature_mask(u32 function, u32 index, int reg)
@@ -334,14 +311,16 @@ static u32 tdx_get_cpuid_cfg_non_feature_mask(u32 function, u32 index, int reg)
static u32 tdx_get_cpuid_cfg_feature_mask(u32 function, u32 index, int reg)
{
+ bool is_indexed = cpuid_function_is_indexed(function);
+
for (int i = 0; i < NR_KVM_CPU_CAPS; i++) {
const struct cpuid_reg *cpuid = &reverse_cpuid[i];
if (!cpuid->function)
continue;
- if (cpuid->function == function && cpuid->index == index &&
- cpuid->reg == reg)
+ if (cpuid->function == function &&
+ (!is_indexed || cpuid->index == index) && cpuid->reg == reg)
return tdx_cpu_cfg_caps[i];
}
@@ -433,6 +412,18 @@ static int init_kvm_tdx_caps(const struct tdx_sys_info_td_conf *td_conf,
return 0;
}
+static bool tdx_is_unsupported_cpuid_entry(const struct kvm_cpuid_entry2 *entry)
+{
+ if (cpuid_function_is_indexed(entry->function) !=
+ !!(entry->flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX))
+ return true;
+
+ return (entry->eax & ~tdx_get_cpuid_cfg_mask(entry->function, entry->index, CPUID_EAX)) ||
+ (entry->ebx & ~tdx_get_cpuid_cfg_mask(entry->function, entry->index, CPUID_EBX)) ||
+ (entry->ecx & ~tdx_get_cpuid_cfg_mask(entry->function, entry->index, CPUID_ECX)) ||
+ (entry->edx & ~tdx_get_cpuid_cfg_mask(entry->function, entry->index, CPUID_EDX));
+}
+
/*
* Some SEAMCALLs acquire the TDX module globally, and can fail with
* TDX_OPERAND_BUSY. Use a global mutex to serialize these SEAMCALLs.
--
2.46.0
next prev parent reply other threads:[~2026-10-28 8:13 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 8:16 [PATCH v6 0/4] KVM: TDX: Validate directly configurable CPUID bits Binbin Wu
2026-10-28 8:16 ` [PATCH v6 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM Binbin Wu
2026-10-28 8:16 ` [PATCH v6 2/4] KVM: TDX: Add CORE_CAPABILITIES to the allowlist Binbin Wu
2026-10-28 8:16 ` [PATCH v6 3/4] KVM: TDX: Report only KVM-allowed CPUID bits in KVM_TDX_CAPABILITIES Binbin Wu
2026-10-28 12:49 ` Nikolay Borisov
2026-10-28 8:16 ` Binbin Wu [this message]
2026-10-28 12:49 ` [PATCH v6 4/4] KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM Nikolay Borisov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261028081658.1228484-5-binbin.wu@linux.intel.com \
--to=binbin.wu@linux.intel.com \
--cc=andrew.cooper3@citrix.com \
--cc=chao.gao@intel.com \
--cc=dave.hansen@linux.intel.com \
--cc=dedekind1@gmail.com \
--cc=kas@kernel.org \
--cc=kishen.maloor@intel.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=nik.borisov@suse.com \
--cc=pbonzini@redhat.com \
--cc=rick.p.edgecombe@intel.com \
--cc=seanjc@google.com \
--cc=tony.lindgren@linux.intel.com \
--cc=xiaoyao.li@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.