[PATCH v1 8/8] x86/virt/tdx: Verify the C member size against the metadata field ID

Chao Gao <[email protected]>
Newsgroups dev.linux.lists.linux-coco,org.kernel.vger.kvm,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Each TDX global metadata field ID encodes the size of that field.
read_sys_metadata_table() stores each value at the width recorded in
the table, which TD_SYSINFO_MAP() derives from the destination C member.
Nothing checks that the two agree.

A table entry naming the wrong field ID, or a struct member declared at
the wrong width, would silently truncate the value read from the TDX
module. That is a kernel-side bug rather than a TDX module problem.

Add macros to extract the encoded size from a field ID, and use them in
TD_SYSINFO_MAP() to assert that it matches the member size.  Both are
compile-time constants, so the check costs nothing at runtime.

Note that BUILD_BUG_ON() cannot be used in a structure initializer; use
BUILD_BUG_ON_ZERO() instead, which yields 0 and so can be folded into the
.size initializer without changing its value.

No functional change intended.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Chao Gao <[email protected]>
---
 arch/x86/virt/vmx/tdx/tdx.c |  9 ++++++++-
 arch/x86/virt/vmx/tdx/tdx.h | 15 +++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 4bf21848df62..59099cc15f7a 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -357,11 +357,18 @@ struct tdx_sys_field {
 	u8  size;
 };
 
+/*
+ * The size encoded in the field ID and the size of the destination C
+ * member must agree; BUILD_BUG_ON_ZERO() enforces this at compile time.
+ */
 #define TD_SYSINFO_MAP(_field_id, _struct, _member)				\
 	{									\
 		.field_id = MD_FIELD_ID_##_field_id,				\
 		.offset   = offsetof(struct _struct, _member),			\
-		.size     = sizeof_field(struct _struct, _member),		\
+		.size     = sizeof_field(struct _struct, _member) +		\
+			    BUILD_BUG_ON_ZERO(					\
+				sizeof_field(struct _struct, _member) !=	\
+				MD_FIELD_ID_ELE_SIZE(MD_FIELD_ID_##_field_id)),	\
 	}
 
 /*
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index 5f567cb6c07a..c612b1cf7c14 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -109,6 +109,21 @@
 #define MD_FIELD_ID_CPUID_CONFIG_LEAVES		0x9900000300000400ULL
 #define MD_FIELD_ID_CPUID_CONFIG_VALUES		0x9900000300000500ULL
 
+/*
+ * Sub-field definitions of MD_FIELD_ID.
+ *
+ * See "MD_FIELD_ID (Metadata Field Identifier / Sequence Header)
+ * Definition" in the Intel TDX Module ABI spec.
+ *
+ *  - Bit 33:32: ELEMENT_SIZE_CODE -- log2 of a single metadata
+ *                                    element's size in bytes
+ */
+#define MD_FIELD_ID_ELE_SIZE_CODE(field_id)	\
+	(((field_id) & GENMASK_ULL(33, 32)) >> 32)
+
+#define MD_FIELD_ID_ELE_SIZE(field_id)		\
+	(1 << MD_FIELD_ID_ELE_SIZE_CODE(field_id))
+
 /* TDX page types */
 #define	PT_NDA		0x0
 #define	PT_RSVD		0x1
-- 
2.52.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.