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, adrian.hunter@intel.com,
binbin.wu@linux.intel.com
Subject: [PATCH v5 5/5] KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM
Date: Fri, 16 Oct 2026 17:14:22 +0800 [thread overview]
Message-ID: <20261016091422.3182216-6-binbin.wu@linux.intel.com> (raw)
In-Reply-To: <20261016091422.3182216-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.
Add tdx_has_unsupported_cpuid_cfg_bit() and 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.
As with the existing check, use the subleaf reported by the TDX module to
look up the allowed mask. For leaves without subleaves, the TDX module's
"no subleaf" index is normalized to 0, which matches how such leaves are
tracked in reverse_cpuid[].
Note, the change is user-visible, as KVM_TDX_INIT_VM now rejects some
input that was previously accepted. The ABI itself is 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 dropped 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>
---
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 | 29 +++++++++--------------------
1 file changed, 9 insertions(+), 20 deletions(-)
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index d617d1a0f63b..78ff0170411b 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -275,25 +275,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, u32 index)
-{
- return entry->function == 7 && index == 0 &&
- (entry->ebx & TDX_FEATURE_TSX);
-}
-
-static bool has_waitpkg(const struct kvm_cpuid_entry2 *entry, u32 index)
-{
- return entry->function == 7 && index == 0 &&
- (entry->ecx & __feature_bit(X86_FEATURE_WAITPKG));
-}
-
-static bool tdx_unsupported_cpuid(const struct kvm_cpuid_entry2 *entry, u32 index)
-{
- return has_tsx(entry, index) || has_waitpkg(entry, index);
-}
-
#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)
@@ -2565,6 +2546,14 @@ static int setup_tdparams_eptp_controls(struct kvm_cpuid2 *cpuid,
return 0;
}
+static bool tdx_has_unsupported_cpuid_cfg_bit(const struct kvm_cpuid_entry2 *e, u32 index)
+{
+ return (e->eax & ~tdx_get_cpuid_cfg_mask(e->function, index, CPUID_EAX)) ||
+ (e->ebx & ~tdx_get_cpuid_cfg_mask(e->function, index, CPUID_EBX)) ||
+ (e->ecx & ~tdx_get_cpuid_cfg_mask(e->function, index, CPUID_ECX)) ||
+ (e->edx & ~tdx_get_cpuid_cfg_mask(e->function, index, CPUID_EDX));
+}
+
static int setup_tdparams_cpuids(struct kvm_cpuid2 *cpuid,
struct td_params *td_params)
{
@@ -2594,7 +2583,7 @@ static int setup_tdparams_cpuids(struct kvm_cpuid2 *cpuid,
* not the index of the userspace entry, which may differ if
* KVM_CPUID_FLAG_SIGNIFCANT_INDEX isn't set.
*/
- if (tdx_unsupported_cpuid(entry, tmp.index))
+ if (tdx_has_unsupported_cpuid_cfg_bit(entry, tmp.index))
return -EINVAL;
copy_cnt++;
--
2.46.0
next prev parent reply other threads:[~2026-10-16 9:10 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-16 9:14 [PATCH v5 0/5] KVM: TDX: Validate directly configurable CPUID bits Binbin Wu
2026-10-16 9:14 ` [PATCH v5 1/5] KVM: TDX: Check unsupported CPUID bits against the TDX module's subleaf Binbin Wu
2026-10-16 9:14 ` [PATCH v5 2/5] KVM: TDX: Track configurable CPUID bits allowed by KVM Binbin Wu
2026-10-16 9:14 ` [PATCH v5 3/5] KVM: TDX: Add CORE_CAPABILITIES to the allowlist Binbin Wu
2026-10-16 9:14 ` [PATCH v5 4/5] KVM: TDX: Report only KVM-allowed CPUIDs in KVM_TDX_CAPABILITIES Binbin Wu
2026-10-16 9:14 ` Binbin Wu [this message]
2026-10-16 9:24 ` [PATCH v5 5/5] KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM sashiko-bot
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=20261016091422.3182216-6-binbin.wu@linux.intel.com \
--to=binbin.wu@linux.intel.com \
--cc=adrian.hunter@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox