The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits
@ 2026-06-04  2:33 Binbin Wu
  2026-06-04  2:33 ` [RFC PATCH v2 1/4] KVM: x86: TDX: Track supported " Binbin Wu
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Binbin Wu @ 2026-06-04  2:33 UTC (permalink / raw)
  To: kvm, linux-kernel
  Cc: seanjc, pbonzini, rick.p.edgecombe, xiaoyao.li, chao.gao,
	kai.huang, binbin.wu

Hi,

A host state clobbering feature on new TDX modules/platforms can lead
to host state corruption if KVM does not explicitly save and restore
the related MSR(s) during host/guest transitions. If such a feature is
blindly exposed to and used by TDs, it will result in unexpected behavior
on the host.

The v1 RFC [1] attempted to solve this by introducing a comprehensive
CPUID paranoid verification framework across VMX, SVM, and TDX. However,
as Sean pointed out in [2] and the discussion in the PUCK meeting, this
approach was overly complex and bled too many TDX-specific details into
common KVM code, creating an unnecessary maintenance burden.

This v2 takes a significantly simpler, TDX-contained approach. It strictly
validates only the TDX directly configurable CPUID bits—those reported by
the TDX module in CPUID_CONFIG fields that the VMM can configure for a TD.
This is sufficient to address the host clobbering issue, as no new host
state clobbering features will be fixed-1. All filtering and validation
logic is entirely isolated within TDX code.

Feedback is highly appreciated, particularly on whether this contained
approach strikes an acceptable balance regarding complexity.

Specifically, this series builds a KVM-side allowlist of supported TDX
directly configurable CPUID bits to:
 - Filter KVM_TDX_CAPABILITIES:
   Replace the hardcoded denylist to only report configurable bits that
   KVM explicitly supports.
 - Validate KVM_TDX_INIT_VM:
   Reject any configurable bit that the TDX module allows but KVM does
   not yet support.

With this allowlist, newly added TDX configurable CPUID bits will not be
exposed to userspace until KVM explicitly opts-in after fulfilling the
necessary virtualization requirements.

Open:
- This series doesn't implement validation for KVM_SET_CPUID2.
  TDX has two interfaces for userspace to set CPUID bits: KVM_TDX_INIT_VM
  and KVM_SET_CPUID2. A malicious userspace VMM could lie to KVM through
  KVM_SET_CPUID2 by setting a TDX directly configurable CPUID bit to a
  different value than what it set via KVM_TDX_INIT_VM. KVM does not
  currently use its own view of vCPU capabilities to manage host clobbering
  features for TDs. The consistency check is not a must have action so
  far. It could be added later if KVM really relies on its own view
  to make decisions to manage host clobbering features for TDX.

Changes from v1:
 - Dropped the overarching CPUID paranoid verification framework across
   VMX/SVM/TDX and the opt-in interface. (Sean)
 - Shifted focus entirely to isolating and validating TDX directly
   configurable CPUID bits.

[1] https://lore.kernel.org/kvm/20260417073610.3246316-1-binbin.wu@linux.intel.com/
[2] https://lore.kernel.org/kvm/agsiQGikhZA0CGTY@google.com/

Binbin Wu (4):
  KVM: x86: TDX: Track supported configurable CPUID bits
  KVM: x86: TDX: Hide unsupported configurable CPUID bits
  KVM: x86: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM
  KVM: x86: TDX: Report CORE_CAPABILITIES as supported

 arch/x86/kvm/vmx/tdx.c | 251 +++++++++++++++++++++++++++++++++++------
 1 file changed, 214 insertions(+), 37 deletions(-)


base-commit: d4bfaa66fa171089b9b9fb2dc17af9245f2b9b34
-- 
2.46.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [RFC PATCH v2 1/4] KVM: x86: TDX: Track supported configurable CPUID bits
  2026-06-04  2:33 [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits Binbin Wu
@ 2026-06-04  2:33 ` Binbin Wu
  2026-06-25 17:04   ` Sean Christopherson
  2026-06-04  2:33 ` [RFC PATCH v2 2/4] KVM: x86: TDX: Hide unsupported " Binbin Wu
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Binbin Wu @ 2026-06-04  2:33 UTC (permalink / raw)
  To: kvm, linux-kernel
  Cc: seanjc, pbonzini, rick.p.edgecombe, xiaoyao.li, chao.gao,
	kai.huang, binbin.wu

Build an allowlist for TDX directly configurable CPUID bits that are
supported by KVM.

The TDX module reports a set of CPUID bits that the VMM can directly
configure for a TD, but KVM cannot blindly trust and expose all
module-supported bits to userspace. Certain features imply additional
architectural state (such as one or more host state clobbering MSRs)
that KVM must explicitly manage across host/guest transitions to
prevent host state corruption.

To safely manage this, track the specific subset of configurable CPUID
bits that KVM supports by initializing multi-bit fields statically and
populating individual feature bits dynamically during TDX hardware
setup.

For better readability and maintainability, define a macro
tdx_cpu_cfg_cap_init() to initialize the feature bits.

Subsequent patches will use this allowlist to consistently filter
KVM_TDX_CAPABILITIES and reject unsupported userspace input through
KVM_TDX_INIT_VM. This ensures that any newly introduced TDX configurable
CPUID bits remain hidden from userspace until KVM explicitly implements
the required virtualization support.

Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
---
 arch/x86/kvm/vmx/tdx.c | 174 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 174 insertions(+)

diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index ffe9d0db58c5..e0567088ebf5 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -52,6 +52,178 @@
 	__TDX_BUG_ON(__err, #__fn, __kvm, ", " #a1 " 0x%llx, " #a2 ", 0x%llx, " #a3 " 0x%llx", \
 		     a1, a2, a3)
 
+#define TDX_CPUID_IGNORE_INDEX	BIT(0)
+struct tdx_supported_cpuid_reg {
+	u32 function;
+	u32 index;
+	u8 flags;
+	u8 reg;
+	u32 mask;
+};
+
+/*
+ * Multi-bit fields are statically initialized, feature bits are initialized
+ * in tdx_initialize_cpu_cfg_caps().
+ */
+static struct tdx_supported_cpuid_reg tdx_kvm_supported_cpuid[] __ro_after_init = {
+	{ 0x1, 0, 0, CPUID_EAX, GENMASK_U32(27, 16) | GENMASK_U32(13, 0) },
+	{ 0x1, 0, 0, CPUID_EBX, GENMASK_U32(23, 16) },
+	{ 0x1, 0, 0, CPUID_ECX, 0 },
+	{ 0x1, 0, 0, CPUID_EDX, 0 },
+	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EAX, ~GENMASK_U32(13, 10) },
+	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EBX, GENMASK_U32(31, 12) },
+	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_ECX, GENMASK_U32(31, 0) },
+	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EDX, GENMASK_U32(2, 0) },
+	{ 0x7, 0, 0, CPUID_EBX, 0 },
+	{ 0x7, 0, 0, CPUID_ECX, 0 },
+	{ 0x7, 0, 0, CPUID_EDX, 0 },
+	{ 0x7, 1, 0, CPUID_EAX, 0 },
+	{ 0x7, 1, 0, CPUID_EDX, 0 },
+	{ 0x7, 2, 0, CPUID_EDX, 0 },
+	{ 0x18, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EDX, GENMASK_U32(25, 14) },
+	{ 0x1E, 1, 0, CPUID_EAX, 0 },
+	{ 0x1F, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EAX, GENMASK_U32(4, 0) },
+	{ 0x1F, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EBX, GENMASK_U32(15, 0) },
+	{ 0x1F, 0, TDX_CPUID_IGNORE_INDEX, CPUID_ECX, GENMASK_U32(15, 0) },
+	/* See comments in td_init_cpuid_entry2() for CPUID 0x80000008 EAX[23:16]. */
+	{ 0x80000008, 0, 0, CPUID_EAX, GENMASK_U32(23, 16) | GENMASK_U32(7, 0) },
+	{ 0x80000008, 0, 0, CPUID_EBX, 0 },
+};
+
+#define TDX_F(name)					\
+({							\
+	tdx_cpu_cfg_caps |= feature_bit(name);		\
+})
+
+#define tdx_cpu_cfg_cap_init(_func, _index, _reg, feature_initializers...)		\
+do {											\
+	u32 tdx_cpu_cfg_caps = 0;							\
+											\
+	for (int i = 0; i < ARRAY_SIZE(tdx_kvm_supported_cpuid); i++) {			\
+		struct tdx_supported_cpuid_reg *r = &tdx_kvm_supported_cpuid[i];	\
+											\
+		if (r->function == _func && r->index == _index && r->reg == _reg) {	\
+			feature_initializers						\
+			r->mask |= tdx_cpu_cfg_caps;					\
+			break;								\
+		}									\
+	}										\
+											\
+	WARN_ON_ONCE(!tdx_cpu_cfg_caps); 						\
+} while (0)
+
+/* Only for TDX directly configurable CPUID feature bits */
+static void __init tdx_initialize_cpu_cfg_caps(void)
+{
+	tdx_cpu_cfg_cap_init(0x1, 0, CPUID_ECX,
+		TDX_F(MWAIT),
+		TDX_F(TSC_DEADLINE_TIMER),
+		TDX_F(AVX),
+		TDX_F(F16C),
+	);
+
+	tdx_cpu_cfg_cap_init(0x1, 0, CPUID_EDX,
+		TDX_F(MCE),
+		TDX_F(MTRR),
+		TDX_F(MCA),
+		TDX_F(SELFSNOOP),
+	);
+
+	tdx_cpu_cfg_cap_init(0x7, 0, CPUID_EBX,
+		TDX_F(BMI1),
+		/* HLE */
+		TDX_F(BMI2),
+		TDX_F(ERMS),
+		/* RTM */
+		/* CQM */
+		/* RDT-A */
+		TDX_F(AVX512F),
+		TDX_F(AVX512DQ),
+		TDX_F(ADX),
+		TDX_F(AVX512IFMA),
+		TDX_F(AVX512PF),
+		TDX_F(AVX512ER),
+		TDX_F(AVX512CD),
+		TDX_F(AVX512BW),
+		TDX_F(AVX512VL),
+	);
+
+	tdx_cpu_cfg_cap_init(0x7, 0, CPUID_ECX,
+		/* PREFETCHWT1 */
+		TDX_F(UMIP),
+		/* WAITPKG */
+		TDX_F(AVX512_VBMI2),
+		TDX_F(GFNI),
+		TDX_F(VAES),
+		TDX_F(VPCLMULQDQ),
+		TDX_F(AVX512_VNNI),
+		TDX_F(AVX512_BITALG),
+		/* TME */
+		TDX_F(AVX512_VPOPCNTDQ),
+		TDX_F(LA57),
+		TDX_F(RDPID),
+		TDX_F(CLDEMOTE),
+	);
+
+	tdx_cpu_cfg_cap_init(0x7, 0, CPUID_EDX,
+		TDX_F(AVX512_4VNNIW),
+		TDX_F(AVX512_4FMAPS),
+		TDX_F(FSRM),
+		TDX_F(AVX512_VP2INTERSECT),
+		TDX_F(SERIALIZE),
+		TDX_F(TSXLDTRK),
+		/* PCONFIG */
+		/* IA32_CORE_CAPABILITIES */
+	);
+
+	tdx_cpu_cfg_cap_init(0x7, 1, CPUID_EAX,
+		TDX_F(SHA512),
+		TDX_F(SM3),
+		TDX_F(SM4),
+		/* RAO_INT */
+		TDX_F(AVX_VNNI),
+		TDX_F(AVX512_BF16),
+		TDX_F(CMPCCXADD),
+		/* PERFMON */
+		TDX_F(FZRM),
+		TDX_F(FSRS),
+		TDX_F(FSRC),
+		/* FRED */
+		TDX_F(LKGS),
+		TDX_F(WRMSRNS),
+		TDX_F(AMX_FP16),
+		TDX_F(AVX_IFMA),
+		TDX_F(LAM),
+		TDX_F(MOVRS),
+	);
+
+	tdx_cpu_cfg_cap_init(0x7, 1, CPUID_EDX,
+		TDX_F(AVX_VNNI_INT8),
+		TDX_F(AVX_NE_CONVERT),
+		TDX_F(AVX_VNNI_INT16),
+		TDX_F(PREFETCHITI),
+		/* UMSR */
+		/* UIRET loads UIF */
+		TDX_F(AVX10),
+	);
+
+	tdx_cpu_cfg_cap_init(0x7, 2, CPUID_EDX,
+		TDX_F(DDPD_U),
+		TDX_F(MCDT_NO),
+	);
+
+	tdx_cpu_cfg_cap_init(0x1E, 1, CPUID_EAX,
+		TDX_F(AMX_FP8),
+		/* AMX-TRANSPOSE */
+		TDX_F(AMX_TF32),
+		TDX_F(AMX_AVX512),
+		TDX_F(AMX_MOVRS),
+	);
+
+	tdx_cpu_cfg_cap_init(0x80000008, 0, CPUID_EBX,
+		TDX_F(WBNOINVD),
+	);
+}
 
 bool enable_tdx __ro_after_init;
 module_param_named(tdx, enable_tdx, bool, 0444);
@@ -3493,6 +3665,8 @@ int __init tdx_hardware_setup(void)
 		return r;
 	}
 
+	tdx_initialize_cpu_cfg_caps();
+
 	KVM_SANITY_CHECK_VM_STRUCT_SIZE(kvm_tdx);
 
 	vt_x86_ops.vm_size = max_t(unsigned int, vt_x86_ops.vm_size, sizeof(struct kvm_tdx));
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH v2 2/4] KVM: x86: TDX: Hide unsupported configurable CPUID bits
  2026-06-04  2:33 [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits Binbin Wu
  2026-06-04  2:33 ` [RFC PATCH v2 1/4] KVM: x86: TDX: Track supported " Binbin Wu
@ 2026-06-04  2:33 ` Binbin Wu
  2026-06-04  2:33 ` [RFC PATCH v2 3/4] KVM: x86: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM Binbin Wu
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 12+ messages in thread
From: Binbin Wu @ 2026-06-04  2:33 UTC (permalink / raw)
  To: kvm, linux-kernel
  Cc: seanjc, pbonzini, rick.p.edgecombe, xiaoyao.li, chao.gao,
	kai.huang, binbin.wu

Filter the CPUID capabilities reported by KVM_TDX_CAPABILITIES through
KVM's supported TDX configurable CPUID allowlist.

The TDX module reports all configurable CPUID bits it supports for a TD,
but KVM must not expose bits to userspace that it doesn't support.
Blindly exposing unsupported features could lead to host state corruption.

Add a helper get_supported_cfg_cpuid() to retrieve KVM's supported TDX
configurable CPUID bit mask for a given leaf, subleaf, and register.
Additionally, add a comment explicitly noting that the allowlist array
must remain sorted by CPUID function. This allows the helper's linear
search to safely terminate early once it iterates past the target leaf,
optimizing the lookup process.

Replace the existing hardcoded denylist with a secure-by-default approach.
By using the get_supported_cfg_cpuid() helper, KVM now strictly reports
only the configurable CPUID bits it explicitly supports. This ensures
any newly introduced configurable CPUID bits are automatically hidden from
userspace until KVM specifically opts in.

Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
---
 arch/x86/kvm/vmx/tdx.c | 45 +++++++++++++++++++++++-------------------
 1 file changed, 25 insertions(+), 20 deletions(-)

diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index e0567088ebf5..e6bfec87a484 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -64,6 +64,8 @@ struct tdx_supported_cpuid_reg {
 /*
  * Multi-bit fields are statically initialized, feature bits are initialized
  * in tdx_initialize_cpu_cfg_caps().
+ *
+ * Keep the list sorted by CPUID function.
  */
 static struct tdx_supported_cpuid_reg tdx_kvm_supported_cpuid[] __ro_after_init = {
 	{ 0x1, 0, 0, CPUID_EAX, GENMASK_U32(27, 16) | GENMASK_U32(13, 0) },
@@ -300,34 +302,31 @@ static bool has_tsx(const struct kvm_cpuid_entry2 *entry)
 	       (entry->ebx & TDX_FEATURE_TSX);
 }
 
-static void clear_tsx(struct kvm_cpuid_entry2 *entry)
-{
-	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 void clear_waitpkg(struct kvm_cpuid_entry2 *entry)
+static bool tdx_unsupported_cpuid(const struct kvm_cpuid_entry2 *entry)
 {
-	entry->ecx &= ~__feature_bit(X86_FEATURE_WAITPKG);
+	return has_tsx(entry) || has_waitpkg(entry);
 }
 
-static void tdx_clear_unsupported_cpuid(struct kvm_cpuid_entry2 *entry)
+static u32 get_supported_cfg_cpuid(u32 function, u32 index, u8 reg)
 {
-	if (has_tsx(entry))
-		clear_tsx(entry);
+	for (int i = 0; i < ARRAY_SIZE(tdx_kvm_supported_cpuid); i++) {
+		struct tdx_supported_cpuid_reg *r = &tdx_kvm_supported_cpuid[i];
 
-	if (has_waitpkg(entry))
-		clear_waitpkg(entry);
-}
+		if (r->function > function)
+			break;
 
-static bool tdx_unsupported_cpuid(const struct kvm_cpuid_entry2 *entry)
-{
-	return has_tsx(entry) || has_waitpkg(entry);
+		if (r->function == function && r->reg == reg &&
+		    (r->index == index || (r->flags & TDX_CPUID_IGNORE_INDEX)))
+			return r->mask;
+	}
+
+	return 0;
 }
 
 #define KVM_TDX_CPUID_NO_SUBLEAF	((__u32)-1)
@@ -353,8 +352,6 @@ static void td_init_cpuid_entry2(struct kvm_cpuid_entry2 *entry, unsigned char i
 	 */
 	if (entry->function == 0x80000008)
 		entry->eax = tdx_set_guest_phys_addr_bits(entry->eax, 0xff);
-
-	tdx_clear_unsupported_cpuid(entry);
 }
 
 #define TDVMCALLINFO_SETUP_EVENT_NOTIFY_INTERRUPT	BIT(1)
@@ -377,8 +374,16 @@ static int init_kvm_tdx_caps(const struct tdx_sys_info_td_conf *td_conf,
 	caps->user_tdvmcallinfo_1_r11 =
 		TDVMCALLINFO_SETUP_EVENT_NOTIFY_INTERRUPT;
 
-	for (i = 0; i < td_conf->num_cpuid_config; i++)
-		td_init_cpuid_entry2(&caps->cpuid.entries[i], i);
+	for (i = 0; i < td_conf->num_cpuid_config; i++) {
+		struct kvm_cpuid_entry2 *e = &caps->cpuid.entries[i];
+
+		td_init_cpuid_entry2(e, i);
+		/* Only report the configurable bits supported by KVM. */
+		e->eax &= get_supported_cfg_cpuid(e->function, e->index, CPUID_EAX);
+		e->ebx &= get_supported_cfg_cpuid(e->function, e->index, CPUID_EBX);
+		e->ecx &= get_supported_cfg_cpuid(e->function, e->index, CPUID_ECX);
+		e->edx &= get_supported_cfg_cpuid(e->function, e->index, CPUID_EDX);
+	}
 
 	return 0;
 }
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH v2 3/4] KVM: x86: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM
  2026-06-04  2:33 [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits Binbin Wu
  2026-06-04  2:33 ` [RFC PATCH v2 1/4] KVM: x86: TDX: Track supported " Binbin Wu
  2026-06-04  2:33 ` [RFC PATCH v2 2/4] KVM: x86: TDX: Hide unsupported " Binbin Wu
@ 2026-06-04  2:33 ` Binbin Wu
  2026-06-04  2:33 ` [RFC PATCH v2 4/4] KVM: x86: TDX: Report CORE_CAPABILITIES as supported Binbin Wu
  2026-06-22  6:32 ` [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits Binbin Wu
  4 siblings, 0 replies; 12+ messages in thread
From: Binbin Wu @ 2026-06-04  2:33 UTC (permalink / raw)
  To: kvm, linux-kernel
  Cc: seanjc, pbonzini, rick.p.edgecombe, xiaoyao.li, chao.gao,
	kai.huang, binbin.wu

Reject unsupported TDX configurable CPUID bits provided by userspace
during KVM_TDX_INIT_VM.

While the TDX module allows the VMM to configure certain CPUID
features for a TD during initialization, KVM must strictly govern
which features are actually enabled. Allowing userspace to blindly
enable features that KVM does not yet support—particularly those
involving host state clobbering MSRs—could lead to host state
corruption, as KVM is not prepared to manage the associated
architectural state across host/guest transitions.

Replace the hardcoded denylist with a robust validation mechanism. By
leveraging the get_supported_cfg_cpuid() helper, KVM now explicitly
rejects the input if userspace attempts to set any TDX configurable bit
that is not present in KVM's allowlist.

Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
---
 arch/x86/kvm/vmx/tdx.c | 30 ++++++++++--------------------
 1 file changed, 10 insertions(+), 20 deletions(-)

diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index e6bfec87a484..e44a862c6219 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -294,25 +294,6 @@ static u32 tdx_set_guest_phys_addr_bits(const u32 eax, int addr_bits)
 	return (eax & ~GENMASK(23, 16)) | (addr_bits & 0xff) << 16;
 }
 
-#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_unsupported_cpuid(const struct kvm_cpuid_entry2 *entry)
-{
-	return has_tsx(entry) || has_waitpkg(entry);
-}
-
 static u32 get_supported_cfg_cpuid(u32 function, u32 index, u8 reg)
 {
 	for (int i = 0; i < ARRAY_SIZE(tdx_kvm_supported_cpuid); i++) {
@@ -2526,6 +2507,15 @@ static int setup_tdparams_eptp_controls(struct kvm_cpuid2 *cpuid,
 	return 0;
 }
 
+static bool tdx_unsupported_cpuid(const struct kvm_cpuid_entry2 *e,
+				  const struct kvm_cpuid_entry2 *mask)
+{
+	return ((e->eax & mask->eax & (~get_supported_cfg_cpuid(e->function, e->index, CPUID_EAX))) ||
+		(e->ebx & mask->ebx & (~get_supported_cfg_cpuid(e->function, e->index, CPUID_EBX))) ||
+		(e->ecx & mask->ecx & (~get_supported_cfg_cpuid(e->function, e->index, CPUID_ECX))) ||
+		(e->edx & mask->edx & (~get_supported_cfg_cpuid(e->function, e->index, CPUID_EDX))));
+}
+
 static int setup_tdparams_cpuids(struct kvm_cpuid2 *cpuid,
 				 struct td_params *td_params)
 {
@@ -2549,7 +2539,7 @@ static int setup_tdparams_cpuids(struct kvm_cpuid2 *cpuid,
 		if (!entry)
 			continue;
 
-		if (tdx_unsupported_cpuid(entry))
+		if (tdx_unsupported_cpuid(entry, &tmp))
 			return -EINVAL;
 
 		copy_cnt++;
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH v2 4/4] KVM: x86: TDX: Report CORE_CAPABILITIES as supported
  2026-06-04  2:33 [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits Binbin Wu
                   ` (2 preceding siblings ...)
  2026-06-04  2:33 ` [RFC PATCH v2 3/4] KVM: x86: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM Binbin Wu
@ 2026-06-04  2:33 ` Binbin Wu
  2026-06-04  6:53   ` Xiaoyao Li
  2026-06-22  6:32 ` [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits Binbin Wu
  4 siblings, 1 reply; 12+ messages in thread
From: Binbin Wu @ 2026-06-04  2:33 UTC (permalink / raw)
  To: kvm, linux-kernel
  Cc: seanjc, pbonzini, rick.p.edgecombe, xiaoyao.li, chao.gao,
	kai.huang, binbin.wu

Add CORE_CAPABILITIES (CPUID.0x7.0.EDX[30]) to the TDX configurable
CPUID allowlist to accommodate legacy TDX module behavior.

KVM doesn't support MSR_IA32_CORE_CAPS, however, some older TDX specs
define CORE_CAPABILITIES CPUID bit as fixed-1.  As a result, userspace
may expect this bit to be enabled in the TDX module for TDs.  When the
CPUID bit becomes a directly configurable without reporting to the
userspace, it can not be enabled.  To avoid confusing userspace, report
CORE_CAPABILITIES to userspace via KVM_TDX_CAPABILITIES.

Although KVM could determine the real CPUID setting by reading the
metadata via SEAMCALL after KVM_TDX_INIT_VM, doing so is overkill to
cover such a corner case.  If CORE_CAPABILITIES is exposed to a TDX
guest, and the guest reads it, simply return 0.

Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
---
 arch/x86/kvm/vmx/tdx.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index e44a862c6219..58647bb70708 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -175,7 +175,7 @@ static void __init tdx_initialize_cpu_cfg_caps(void)
 		TDX_F(SERIALIZE),
 		TDX_F(TSXLDTRK),
 		/* PCONFIG */
-		/* IA32_CORE_CAPABILITIES */
+		TDX_F(CORE_CAPABILITIES),
 	);
 
 	tdx_cpu_cfg_cap_init(0x7, 1, CPUID_EAX,
@@ -2401,6 +2401,14 @@ int tdx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
 			return 1;
 		msr->data = vcpu->arch.mcg_ext_ctl;
 		return 0;
+	case MSR_IA32_CORE_CAPS:
+		/*
+		 * KVM doesn't support MSR_IA32_CORE_CAPS, however, in some old
+		 * TDX modules, CPUID.0x7.0.EDX[30] is fixed-1. As a workaround,
+		 * just return 0 for this MSR.
+		 */
+		msr->data = 0;
+		return 0;
 	default:
 		if (!tdx_has_emulated_msr(msr->index))
 			return 1;
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH v2 4/4] KVM: x86: TDX: Report CORE_CAPABILITIES as supported
  2026-06-04  2:33 ` [RFC PATCH v2 4/4] KVM: x86: TDX: Report CORE_CAPABILITIES as supported Binbin Wu
@ 2026-06-04  6:53   ` Xiaoyao Li
  2026-06-04  7:20     ` Binbin Wu
  0 siblings, 1 reply; 12+ messages in thread
From: Xiaoyao Li @ 2026-06-04  6:53 UTC (permalink / raw)
  To: Binbin Wu, kvm, linux-kernel
  Cc: seanjc, pbonzini, rick.p.edgecombe, chao.gao, kai.huang

On 6/4/2026 10:33 AM, Binbin Wu wrote:
> Add CORE_CAPABILITIES (CPUID.0x7.0.EDX[30]) to the TDX configurable
> CPUID allowlist to accommodate legacy TDX module behavior.
> 
> KVM doesn't support MSR_IA32_CORE_CAPS, however, some older TDX specs
> define CORE_CAPABILITIES CPUID bit as fixed-1.  As a result, userspace
> may expect this bit to be enabled in the TDX module for TDs.  When the
> CPUID bit becomes a directly configurable without reporting to the
> userspace, it can not be enabled.  To avoid confusing userspace, report
> CORE_CAPABILITIES to userspace via KVM_TDX_CAPABILITIES.
> 
> Although KVM could determine the real CPUID setting by reading the
> metadata via SEAMCALL after KVM_TDX_INIT_VM, doing so is overkill to
> cover such a corner case.  If CORE_CAPABILITIES is exposed to a TDX
> guest, and the guest reads it, simply return 0.

shouldn't this patch be put as patch 02 instead of 04?

Patch 02 and 03 in this series break the old QEMU and then patch 04 
fixes the broken. This is not friendly to the bisect.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH v2 4/4] KVM: x86: TDX: Report CORE_CAPABILITIES as supported
  2026-06-04  6:53   ` Xiaoyao Li
@ 2026-06-04  7:20     ` Binbin Wu
  0 siblings, 0 replies; 12+ messages in thread
From: Binbin Wu @ 2026-06-04  7:20 UTC (permalink / raw)
  To: Xiaoyao Li
  Cc: kvm, linux-kernel, seanjc, pbonzini, rick.p.edgecombe, chao.gao,
	kai.huang



On 6/4/2026 2:53 PM, Xiaoyao Li wrote:
> On 6/4/2026 10:33 AM, Binbin Wu wrote:
>> Add CORE_CAPABILITIES (CPUID.0x7.0.EDX[30]) to the TDX configurable
>> CPUID allowlist to accommodate legacy TDX module behavior.
>>
>> KVM doesn't support MSR_IA32_CORE_CAPS, however, some older TDX specs
>> define CORE_CAPABILITIES CPUID bit as fixed-1.  As a result, userspace
>> may expect this bit to be enabled in the TDX module for TDs.  When the
>> CPUID bit becomes a directly configurable without reporting to the
>> userspace, it can not be enabled.  To avoid confusing userspace, report
>> CORE_CAPABILITIES to userspace via KVM_TDX_CAPABILITIES.
>>
>> Although KVM could determine the real CPUID setting by reading the
>> metadata via SEAMCALL after KVM_TDX_INIT_VM, doing so is overkill to
>> cover such a corner case.  If CORE_CAPABILITIES is exposed to a TDX
>> guest, and the guest reads it, simply return 0.
> 
> shouldn't this patch be put as patch 02 instead of 04?
> 
> Patch 02 and 03 in this series break the old QEMU and then patch 04 fixes the broken. This is not friendly to the bisect.

Good point.

I will reorder the patch in the later version if the direction of this
patch series is acked by maintainers.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits
  2026-06-04  2:33 [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits Binbin Wu
                   ` (3 preceding siblings ...)
  2026-06-04  2:33 ` [RFC PATCH v2 4/4] KVM: x86: TDX: Report CORE_CAPABILITIES as supported Binbin Wu
@ 2026-06-22  6:32 ` Binbin Wu
  2026-06-25 17:04   ` Sean Christopherson
  4 siblings, 1 reply; 12+ messages in thread
From: Binbin Wu @ 2026-06-22  6:32 UTC (permalink / raw)
  To: seanjc
  Cc: kvm, linux-kernel, pbonzini, rick.p.edgecombe, xiaoyao.li,
	chao.gao, kai.huang

On 6/4/2026 10:33 AM, Binbin Wu wrote:
> Hi,
> 
> A host state clobbering feature on new TDX modules/platforms can lead
> to host state corruption if KVM does not explicitly save and restore
> the related MSR(s) during host/guest transitions. If such a feature is
> blindly exposed to and used by TDs, it will result in unexpected behavior
> on the host.
> 
> The v1 RFC [1] attempted to solve this by introducing a comprehensive
> CPUID paranoid verification framework across VMX, SVM, and TDX. However,
> as Sean pointed out in [2] and the discussion in the PUCK meeting, this
> approach was overly complex and bled too many TDX-specific details into
> common KVM code, creating an unnecessary maintenance burden.
> 
> This v2 takes a significantly simpler, TDX-contained approach. It strictly
> validates only the TDX directly configurable CPUID bits—those reported by
> the TDX module in CPUID_CONFIG fields that the VMM can configure for a TD.
> This is sufficient to address the host clobbering issue, as no new host
> state clobbering features will be fixed-1. All filtering and validation
> logic is entirely isolated within TDX code.
> 
> Feedback is highly appreciated, particularly on whether this contained
> approach strikes an acceptable balance regarding complexity.

Hi Sean,

Do you think this proposal is the direction to go?

> 
> Specifically, this series builds a KVM-side allowlist of supported TDX
> directly configurable CPUID bits to:
>  - Filter KVM_TDX_CAPABILITIES:
>    Replace the hardcoded denylist to only report configurable bits that
>    KVM explicitly supports.
>  - Validate KVM_TDX_INIT_VM:
>    Reject any configurable bit that the TDX module allows but KVM does
>    not yet support.
> 
> With this allowlist, newly added TDX configurable CPUID bits will not be
> exposed to userspace until KVM explicitly opts-in after fulfilling the
> necessary virtualization requirements.
> 
> Open:
> - This series doesn't implement validation for KVM_SET_CPUID2.
>   TDX has two interfaces for userspace to set CPUID bits: KVM_TDX_INIT_VM
>   and KVM_SET_CPUID2. A malicious userspace VMM could lie to KVM through
>   KVM_SET_CPUID2 by setting a TDX directly configurable CPUID bit to a
>   different value than what it set via KVM_TDX_INIT_VM. KVM does not
>   currently use its own view of vCPU capabilities to manage host clobbering
>   features for TDs. The consistency check is not a must have action so
>   far. It could be added later if KVM really relies on its own view
>   to make decisions to manage host clobbering features for TDX.
> 
> Changes from v1:
>  - Dropped the overarching CPUID paranoid verification framework across
>    VMX/SVM/TDX and the opt-in interface. (Sean)
>  - Shifted focus entirely to isolating and validating TDX directly
>    configurable CPUID bits.
> 
> [1] https://lore.kernel.org/kvm/20260417073610.3246316-1-binbin.wu@linux.intel.com/
> [2] https://lore.kernel.org/kvm/agsiQGikhZA0CGTY@google.com/
> 
> Binbin Wu (4):
>   KVM: x86: TDX: Track supported configurable CPUID bits
>   KVM: x86: TDX: Hide unsupported configurable CPUID bits
>   KVM: x86: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM
>   KVM: x86: TDX: Report CORE_CAPABILITIES as supported
> 
>  arch/x86/kvm/vmx/tdx.c | 251 +++++++++++++++++++++++++++++++++++------
>  1 file changed, 214 insertions(+), 37 deletions(-)
> 
> 
> base-commit: d4bfaa66fa171089b9b9fb2dc17af9245f2b9b34


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH v2 1/4] KVM: x86: TDX: Track supported configurable CPUID bits
  2026-06-04  2:33 ` [RFC PATCH v2 1/4] KVM: x86: TDX: Track supported " Binbin Wu
@ 2026-06-25 17:04   ` Sean Christopherson
  2026-06-29  3:02     ` Binbin Wu
  0 siblings, 1 reply; 12+ messages in thread
From: Sean Christopherson @ 2026-06-25 17:04 UTC (permalink / raw)
  To: Binbin Wu
  Cc: kvm, linux-kernel, pbonzini, rick.p.edgecombe, xiaoyao.li,
	chao.gao, kai.huang

On Thu, Jun 04, 2026, Binbin Wu wrote:
> ---
>  arch/x86/kvm/vmx/tdx.c | 174 +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 174 insertions(+)
> 
> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> index ffe9d0db58c5..e0567088ebf5 100644
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
> @@ -52,6 +52,178 @@
>  	__TDX_BUG_ON(__err, #__fn, __kvm, ", " #a1 " 0x%llx, " #a2 ", 0x%llx, " #a3 " 0x%llx", \
>  		     a1, a2, a3)
>  
> +#define TDX_CPUID_IGNORE_INDEX	BIT(0)
> +struct tdx_supported_cpuid_reg {
> +	u32 function;
> +	u32 index;
> +	u8 flags;
> +	u8 reg;
> +	u32 mask;
> +};
> +
> +/*
> + * Multi-bit fields are statically initialized, feature bits are initialized
> + * in tdx_initialize_cpu_cfg_caps().
> + */
> +static struct tdx_supported_cpuid_reg tdx_kvm_supported_cpuid[] __ro_after_init = {
> +	{ 0x1, 0, 0, CPUID_EAX, GENMASK_U32(27, 16) | GENMASK_U32(13, 0) },
> +	{ 0x1, 0, 0, CPUID_EBX, GENMASK_U32(23, 16) },
> +	{ 0x1, 0, 0, CPUID_ECX, 0 },
> +	{ 0x1, 0, 0, CPUID_EDX, 0 },
> +	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EAX, ~GENMASK_U32(13, 10) },
> +	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EBX, GENMASK_U32(31, 12) },
> +	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_ECX, GENMASK_U32(31, 0) },
> +	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EDX, GENMASK_U32(2, 0) },
> +	{ 0x7, 0, 0, CPUID_EBX, 0 },
> +	{ 0x7, 0, 0, CPUID_ECX, 0 },
> +	{ 0x7, 0, 0, CPUID_EDX, 0 },
> +	{ 0x7, 1, 0, CPUID_EAX, 0 },
> +	{ 0x7, 1, 0, CPUID_EDX, 0 },
> +	{ 0x7, 2, 0, CPUID_EDX, 0 },
> +	{ 0x18, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EDX, GENMASK_U32(25, 14) },
> +	{ 0x1E, 1, 0, CPUID_EAX, 0 },
> +	{ 0x1F, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EAX, GENMASK_U32(4, 0) },
> +	{ 0x1F, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EBX, GENMASK_U32(15, 0) },
> +	{ 0x1F, 0, TDX_CPUID_IGNORE_INDEX, CPUID_ECX, GENMASK_U32(15, 0) },
> +	/* See comments in td_init_cpuid_entry2() for CPUID 0x80000008 EAX[23:16]. */
> +	{ 0x80000008, 0, 0, CPUID_EAX, GENMASK_U32(23, 16) | GENMASK_U32(7, 0) },
> +	{ 0x80000008, 0, 0, CPUID_EBX, 0 },

For non-feature bits, I think I would rather handle them entirely at runtime via
switch statement(s).  Realistically, CPUID.0x1.E{A,B}X are never going to be
repurposed to hold feature bits, and so generating a mask of allowed bits adds
unnecessary cognitive load and maintenance.  Ditto for CPUID 0x4, 0x18, and 0x1F.

CPUID.0x1E is a bit different because it's kinda sorta a feature?  That one is
probably worth restricting, but again that's easy to do in a case-statement.

Then for the feature bits, there should be no need to define a separate structure,
just do "u32 kvm_tdx_cpu_caps[NR_KVM_CPU_CAPS]".  Then KVM can even further
restrict that array with kvm_cpu_caps (though it might take some creativity to
deal with things like MWAIT).  Because generally speaking, KVM shouldn't allow
features that KVM doesn't support for non-TDX VMs.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits
  2026-06-22  6:32 ` [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits Binbin Wu
@ 2026-06-25 17:04   ` Sean Christopherson
  2026-06-29  3:02     ` Binbin Wu
  0 siblings, 1 reply; 12+ messages in thread
From: Sean Christopherson @ 2026-06-25 17:04 UTC (permalink / raw)
  To: Binbin Wu
  Cc: kvm, linux-kernel, pbonzini, rick.p.edgecombe, xiaoyao.li,
	chao.gao, kai.huang

On Mon, Jun 22, 2026, Binbin Wu wrote:
> On 6/4/2026 10:33 AM, Binbin Wu wrote:
> > Hi,
> > 
> > A host state clobbering feature on new TDX modules/platforms can lead
> > to host state corruption if KVM does not explicitly save and restore
> > the related MSR(s) during host/guest transitions. If such a feature is
> > blindly exposed to and used by TDs, it will result in unexpected behavior
> > on the host.
> > 
> > The v1 RFC [1] attempted to solve this by introducing a comprehensive
> > CPUID paranoid verification framework across VMX, SVM, and TDX. However,
> > as Sean pointed out in [2] and the discussion in the PUCK meeting, this
> > approach was overly complex and bled too many TDX-specific details into
> > common KVM code, creating an unnecessary maintenance burden.
> > 
> > This v2 takes a significantly simpler, TDX-contained approach. It strictly
> > validates only the TDX directly configurable CPUID bits—those reported by
> > the TDX module in CPUID_CONFIG fields that the VMM can configure for a TD.
> > This is sufficient to address the host clobbering issue, as no new host
> > state clobbering features will be fixed-1. All filtering and validation
> > logic is entirely isolated within TDX code.
> > 
> > Feedback is highly appreciated, particularly on whether this contained
> > approach strikes an acceptable balance regarding complexity.
> 
> Hi Sean,
> 
> Do you think this proposal is the direction to go?

Yeah, the basic gist looks good.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH v2 1/4] KVM: x86: TDX: Track supported configurable CPUID bits
  2026-06-25 17:04   ` Sean Christopherson
@ 2026-06-29  3:02     ` Binbin Wu
  0 siblings, 0 replies; 12+ messages in thread
From: Binbin Wu @ 2026-06-29  3:02 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: kvm, linux-kernel, pbonzini, rick.p.edgecombe, xiaoyao.li,
	chao.gao, kai.huang

On 6/26/2026 1:04 AM, Sean Christopherson wrote:
> On Thu, Jun 04, 2026, Binbin Wu wrote:
>> ---
>>  arch/x86/kvm/vmx/tdx.c | 174 +++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 174 insertions(+)
>>
>> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
>> index ffe9d0db58c5..e0567088ebf5 100644
>> --- a/arch/x86/kvm/vmx/tdx.c
>> +++ b/arch/x86/kvm/vmx/tdx.c
>> @@ -52,6 +52,178 @@
>>  	__TDX_BUG_ON(__err, #__fn, __kvm, ", " #a1 " 0x%llx, " #a2 ", 0x%llx, " #a3 " 0x%llx", \
>>  		     a1, a2, a3)
>>  
>> +#define TDX_CPUID_IGNORE_INDEX	BIT(0)
>> +struct tdx_supported_cpuid_reg {
>> +	u32 function;
>> +	u32 index;
>> +	u8 flags;
>> +	u8 reg;
>> +	u32 mask;
>> +};
>> +
>> +/*
>> + * Multi-bit fields are statically initialized, feature bits are initialized
>> + * in tdx_initialize_cpu_cfg_caps().
>> + */
>> +static struct tdx_supported_cpuid_reg tdx_kvm_supported_cpuid[] __ro_after_init = {
>> +	{ 0x1, 0, 0, CPUID_EAX, GENMASK_U32(27, 16) | GENMASK_U32(13, 0) },
>> +	{ 0x1, 0, 0, CPUID_EBX, GENMASK_U32(23, 16) },
>> +	{ 0x1, 0, 0, CPUID_ECX, 0 },
>> +	{ 0x1, 0, 0, CPUID_EDX, 0 },
>> +	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EAX, ~GENMASK_U32(13, 10) },
>> +	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EBX, GENMASK_U32(31, 12) },
>> +	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_ECX, GENMASK_U32(31, 0) },
>> +	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EDX, GENMASK_U32(2, 0) },
>> +	{ 0x7, 0, 0, CPUID_EBX, 0 },
>> +	{ 0x7, 0, 0, CPUID_ECX, 0 },
>> +	{ 0x7, 0, 0, CPUID_EDX, 0 },
>> +	{ 0x7, 1, 0, CPUID_EAX, 0 },
>> +	{ 0x7, 1, 0, CPUID_EDX, 0 },
>> +	{ 0x7, 2, 0, CPUID_EDX, 0 },
>> +	{ 0x18, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EDX, GENMASK_U32(25, 14) },
>> +	{ 0x1E, 1, 0, CPUID_EAX, 0 },
>> +	{ 0x1F, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EAX, GENMASK_U32(4, 0) },
>> +	{ 0x1F, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EBX, GENMASK_U32(15, 0) },
>> +	{ 0x1F, 0, TDX_CPUID_IGNORE_INDEX, CPUID_ECX, GENMASK_U32(15, 0) },
>> +	/* See comments in td_init_cpuid_entry2() for CPUID 0x80000008 EAX[23:16]. */
>> +	{ 0x80000008, 0, 0, CPUID_EAX, GENMASK_U32(23, 16) | GENMASK_U32(7, 0) },
>> +	{ 0x80000008, 0, 0, CPUID_EBX, 0 },
> 
> For non-feature bits, I think I would rather handle them entirely at runtime via
> switch statement(s).  Realistically, CPUID.0x1.E{A,B}X are never going to be
> repurposed to hold feature bits, and so generating a mask of allowed bits adds
> unnecessary cognitive load and maintenance.  Ditto for CPUID 0x4, 0x18, and 0x1F.

Yes, it's a bit over-engineered with the matter of fact that these are never going
to hold feature bit.

> 
> CPUID.0x1E is a bit different because it's kinda sorta a feature?  That one is
> probably worth restricting, but again that's easy to do in a case-statement.

Only CPUID.0x1E.EAX has TDX directly configurable bits currently, no special
handling needed for the rest of CPUID.0x1E.

> 
> Then for the feature bits, there should be no need to define a separate structure,
> just do "u32 kvm_tdx_cpu_caps[NR_KVM_CPU_CAPS]".  Then KVM can even further
> restrict that array with kvm_cpu_caps (though it might take some creativity to
> deal with things like MWAIT).  Because generally speaking, KVM shouldn't allow
> features that KVM doesn't support for non-TDX VMs.
> 

OK, will go this direction in the next version.
Thanks for the suggestions.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits
  2026-06-25 17:04   ` Sean Christopherson
@ 2026-06-29  3:02     ` Binbin Wu
  0 siblings, 0 replies; 12+ messages in thread
From: Binbin Wu @ 2026-06-29  3:02 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: kvm, linux-kernel, pbonzini, rick.p.edgecombe, xiaoyao.li,
	chao.gao, kai.huang

On 6/26/2026 1:04 AM, Sean Christopherson wrote:
> On Mon, Jun 22, 2026, Binbin Wu wrote:
>> On 6/4/2026 10:33 AM, Binbin Wu wrote:
>>> Hi,
>>>
>>> A host state clobbering feature on new TDX modules/platforms can lead
>>> to host state corruption if KVM does not explicitly save and restore
>>> the related MSR(s) during host/guest transitions. If such a feature is
>>> blindly exposed to and used by TDs, it will result in unexpected behavior
>>> on the host.
>>>
>>> The v1 RFC [1] attempted to solve this by introducing a comprehensive
>>> CPUID paranoid verification framework across VMX, SVM, and TDX. However,
>>> as Sean pointed out in [2] and the discussion in the PUCK meeting, this
>>> approach was overly complex and bled too many TDX-specific details into
>>> common KVM code, creating an unnecessary maintenance burden.
>>>
>>> This v2 takes a significantly simpler, TDX-contained approach. It strictly
>>> validates only the TDX directly configurable CPUID bits—those reported by
>>> the TDX module in CPUID_CONFIG fields that the VMM can configure for a TD.
>>> This is sufficient to address the host clobbering issue, as no new host
>>> state clobbering features will be fixed-1. All filtering and validation
>>> logic is entirely isolated within TDX code.
>>>
>>> Feedback is highly appreciated, particularly on whether this contained
>>> approach strikes an acceptable balance regarding complexity.
>>
>> Hi Sean,
>>
>> Do you think this proposal is the direction to go?
> 
> Yeah, the basic gist looks good.
> 

Thanks for confirming this!

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-06-29  3:02 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-04  2:33 [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits Binbin Wu
2026-06-04  2:33 ` [RFC PATCH v2 1/4] KVM: x86: TDX: Track supported " Binbin Wu
2026-06-25 17:04   ` Sean Christopherson
2026-06-29  3:02     ` Binbin Wu
2026-06-04  2:33 ` [RFC PATCH v2 2/4] KVM: x86: TDX: Hide unsupported " Binbin Wu
2026-06-04  2:33 ` [RFC PATCH v2 3/4] KVM: x86: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM Binbin Wu
2026-06-04  2:33 ` [RFC PATCH v2 4/4] KVM: x86: TDX: Report CORE_CAPABILITIES as supported Binbin Wu
2026-06-04  6:53   ` Xiaoyao Li
2026-06-04  7:20     ` Binbin Wu
2026-06-22  6:32 ` [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits Binbin Wu
2026-06-25 17:04   ` Sean Christopherson
2026-06-29  3:02     ` Binbin Wu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox