From 63d1e876e7125b9eb9027bc6cc6976d038a18d69 Mon Sep 17 00:00:00 2001 From: Alice Chen Date: Mon, 26 Jan 2026 15:12:53 -0800 Subject: [PATCH 1/9] add some basic defs for new td info header --- igvm_defs/src/lib.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/igvm_defs/src/lib.rs b/igvm_defs/src/lib.rs index 7d11fd2..c032a3a 100644 --- a/igvm_defs/src/lib.rs +++ b/igvm_defs/src/lib.rs @@ -248,6 +248,9 @@ pub enum IgvmVariableHeaderType { /// A page table relocation region described by /// [`IGVM_VHS_PAGE_TABLE_RELOCATION`]. IGVM_VHT_PAGE_TABLE_RELOCATION_REGION = 0x103, + /// A page table relocation region described by + /// [`IGVM_VHS_TD_INFO`]. + IGVM_VHT_TD_INFO = 0x104, // These are IGVM_VHT_RANGE_DIRECTIVE structures. /// A parameter area structure described by [`IGVM_VHS_PARAMETER_AREA`]. @@ -646,6 +649,21 @@ pub struct IGVM_VHS_PAGE_TABLE_RELOCATION { pub used_size: u64, } +/// Optional launch time configurations for VMs running on TDX platform. +/// +/// The XFAM (Extended Features Allowed Mask) value specifies a mask of CPU extended features +/// that the TD is allowed to use. If the XFAM value is invalid or not supported by the host, +/// the igvm file will fail to load. If the host overrides the specified XFAM value, +/// attestation will fail. +/// +/// Only supported on TDX platforms. +#[bitfield(u64)] +#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)] +pub struct IGVM_VHS_TD_INFO { + // XFAM value + pub xfam: u64, +} + /// This structure defines a region of memory that can be used for holding /// parameters to be passed into the guest. Parameter areas are created with /// this structure, then parameters may be imported via parameter structures From 97baabc61c5aedf4c468ed45c06f41292c4a8ffb Mon Sep 17 00:00:00 2001 From: Alice Chen Date: Mon, 26 Jan 2026 15:35:12 -0800 Subject: [PATCH 2/9] add parsing --- igvm/src/lib.rs | 17 +++++++++++++++++ igvm_defs/src/lib.rs | 6 +++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/igvm/src/lib.rs b/igvm/src/lib.rs index 9a52865..b58fe50 100644 --- a/igvm/src/lib.rs +++ b/igvm/src/lib.rs @@ -344,6 +344,10 @@ pub enum IgvmInitializationHeader { vp_index: u16, vtl: Vtl, }, + /// Represents an [IGVM_VHS_TD_INFO]. + TdInfo { + xfam: u64, + }, } impl IgvmInitializationHeader { @@ -665,6 +669,19 @@ impl IgvmInitializationHeader { variable_headers, ); } + IgvmInitializationHeader::TdInfo { + xfam, + } => { + let info = IGVM_VHS_TD_INFO { + xfam: *xfam + }; + + append_header( + &info, + IgvmVariableHeaderType::IGVM_VHT_TD_INFO, + variable_headers, + ); + } } Ok(()) diff --git a/igvm_defs/src/lib.rs b/igvm_defs/src/lib.rs index c032a3a..a7aac9c 100644 --- a/igvm_defs/src/lib.rs +++ b/igvm_defs/src/lib.rs @@ -248,7 +248,7 @@ pub enum IgvmVariableHeaderType { /// A page table relocation region described by /// [`IGVM_VHS_PAGE_TABLE_RELOCATION`]. IGVM_VHT_PAGE_TABLE_RELOCATION_REGION = 0x103, - /// A page table relocation region described by + /// TDX launch time configurations as described by /// [`IGVM_VHS_TD_INFO`]. IGVM_VHT_TD_INFO = 0x104, @@ -657,10 +657,10 @@ pub struct IGVM_VHS_PAGE_TABLE_RELOCATION { /// attestation will fail. /// /// Only supported on TDX platforms. -#[bitfield(u64)] +#[repr(C)] #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)] pub struct IGVM_VHS_TD_INFO { - // XFAM value + /// XFAM for CPU extended features setting. pub xfam: u64, } From 2e9a9b6d291485dc621dee7a2030a361b80bbd68 Mon Sep 17 00:00:00 2001 From: Alice Chen Date: Mon, 26 Jan 2026 17:22:11 -0800 Subject: [PATCH 3/9] fix compile errs --- igvm/src/lib.rs | 40 +++++++++++++++++++++++++++ igvm_c/cbindgen_igvm_defs.toml | 49 +++++++++++++++++----------------- igvm_c/sample/dump_igvm.c | 10 ++++++- igvm_defs/src/lib.rs | 6 ++++- 4 files changed, 79 insertions(+), 26 deletions(-) diff --git a/igvm/src/lib.rs b/igvm/src/lib.rs index b58fe50..4182ca7 100644 --- a/igvm/src/lib.rs +++ b/igvm/src/lib.rs @@ -346,6 +346,7 @@ pub enum IgvmInitializationHeader { }, /// Represents an [IGVM_VHS_TD_INFO]. TdInfo { + compatibility_mask: u32, xfam: u64, }, } @@ -361,6 +362,9 @@ impl IgvmInitializationHeader { IgvmInitializationHeader::PageTableRelocationRegion { .. } => { size_of::() } + IgvmInitializationHeader::TdInfo { .. } => { + size_of::() + } }; size_of::() + additional @@ -380,6 +384,9 @@ impl IgvmInitializationHeader { IgvmInitializationHeader::PageTableRelocationRegion { .. } => { IgvmVariableHeaderType::IGVM_VHT_PAGE_TABLE_RELOCATION_REGION } + IgvmInitializationHeader::TdInfo { .. } => { + IgvmVariableHeaderType::IGVM_VHT_TD_INFO + } } } @@ -458,6 +465,12 @@ impl IgvmInitializationHeader { Ok(()) } + IgvmInitializationHeader::TdInfo { + compatibility_mask: _, + xfam: _, + } => { + Ok(()) + } } } @@ -554,6 +567,24 @@ impl IgvmInitializationHeader { vtl: vtl.try_into().map_err(|_| BinaryHeaderError::InvalidVtl)?, } } + IgvmVariableHeaderType::IGVM_VHT_TD_INFO + if length == size_of::() => + { + let IGVM_VHS_TD_INFO { + compatibility_mask, + reserved, + xfam, + } = read_header(&mut variable_headers)?; + + if reserved != 0 { + return Err(BinaryHeaderError::ReservedNotZero); + } + + IgvmInitializationHeader::TdInfo { + compatibility_mask, + xfam, + } + } _ => return Err(BinaryHeaderError::InvalidVariableHeaderType), }; @@ -576,6 +607,9 @@ impl IgvmInitializationHeader { PageTableRelocationRegion { compatibility_mask, .. } => Some(*compatibility_mask), + TdInfo { + compatibility_mask, .. + } => Some(*compatibility_mask), } } @@ -670,9 +704,12 @@ impl IgvmInitializationHeader { ); } IgvmInitializationHeader::TdInfo { + compatibility_mask, xfam, } => { let info = IGVM_VHS_TD_INFO { + compatibility_mask: *compatibility_mask, + reserved: 0, xfam: *xfam }; @@ -3346,6 +3383,9 @@ impl IgvmFile { IgvmInitializationHeader::PageTableRelocationRegion { compatibility_mask, .. } => fixup_mask(compatibility_mask), + IgvmInitializationHeader::TdInfo { + compatibility_mask, .. + } => fixup_mask(compatibility_mask), } } diff --git a/igvm_c/cbindgen_igvm_defs.toml b/igvm_c/cbindgen_igvm_defs.toml index c9b8bc8..6e2018d 100644 --- a/igvm_c/cbindgen_igvm_defs.toml +++ b/igvm_c/cbindgen_igvm_defs.toml @@ -7,7 +7,7 @@ language = "C" header = """ -/* +/* * SPDX-License-Identifier: MIT OR Apache-2.0 * * Copyright (c) 2023 SUSE LLC @@ -52,30 +52,31 @@ typedef uint32_t IGVM_U32_LE; """ [export] -include = ["IGVM_FIXED_HEADER", +include = ["IGVM_FIXED_HEADER", "IGVM_VHS_VARIABLE_HEADER", - "IGVM_VHS_SUPPORTED_PLATFORM", - "IGVM_VHS_GUEST_POLICY", - "GuestPolicy", - "SnpPolicy", - "TdxPolicy", - "IGVM_VHS_RELOCATABLE_REGION", - "IGVM_VHS_PAGE_TABLE_RELOCATION", - "IGVM_VHS_PARAMETER_AREA", - "IGVM_VHS_PAGE_DATA", - "IGVM_VHS_PARAMETER_INSERT", - "IGVM_VHS_PARAMETER", - "IGVM_VHS_VP_CONTEXT", - "VbsVpContextHeader", - "VbsVpContextRegister", - "IGVM_VHS_REQUIRED_MEMORY", - "IGVM_VHS_MEMORY_RANGE", - "IGVM_VHS_MMIO_RANGES", - "IGVM_VHS_SNP_ID_BLOCK_SIGNATURE", - "IGVM_VHS_SNP_ID_BLOCK_PUBLIC_KEY", - "IGVM_VHS_SNP_ID_BLOCK", - "IGVM_VHS_VBS_MEASUREMENT", - "IGVM_VHS_MEMORY_MAP_ENTRY", + "IGVM_VHS_SUPPORTED_PLATFORM", + "IGVM_VHS_GUEST_POLICY", + "GuestPolicy", + "SnpPolicy", + "TdxPolicy", + "IGVM_VHS_RELOCATABLE_REGION", + "IGVM_VHS_PAGE_TABLE_RELOCATION", + "IGVM_VHS_TD_INFO", + "IGVM_VHS_PARAMETER_AREA", + "IGVM_VHS_PAGE_DATA", + "IGVM_VHS_PARAMETER_INSERT", + "IGVM_VHS_PARAMETER", + "IGVM_VHS_VP_CONTEXT", + "VbsVpContextHeader", + "VbsVpContextRegister", + "IGVM_VHS_REQUIRED_MEMORY", + "IGVM_VHS_MEMORY_RANGE", + "IGVM_VHS_MMIO_RANGES", + "IGVM_VHS_SNP_ID_BLOCK_SIGNATURE", + "IGVM_VHS_SNP_ID_BLOCK_PUBLIC_KEY", + "IGVM_VHS_SNP_ID_BLOCK", + "IGVM_VHS_VBS_MEASUREMENT", + "IGVM_VHS_MEMORY_MAP_ENTRY", "IGVM_VHS_ERROR_RANGE"] exclude = ["IgvmPageDataFlags", "RequiredMemoryFlags", "MemoryMapEntryFlags"] diff --git a/igvm_c/sample/dump_igvm.c b/igvm_c/sample/dump_igvm.c index 3611d01..1cb2049 100644 --- a/igvm_c/sample/dump_igvm.c +++ b/igvm_c/sample/dump_igvm.c @@ -1,4 +1,4 @@ -/* +/* * SPDX-License-Identifier: MIT OR Apache-2.0 * * Copyright (c) 2023 SUSE LLC @@ -61,6 +61,8 @@ static char *igvm_type_to_text(uint32_t type) return "IGVM_VHT_RELOCATABLE_REGION"; case IGVM_VHT_PAGE_TABLE_RELOCATION_REGION: return "IGVM_VHT_PAGE_TABLE_RELOCATION_REGION"; + case IGVM_VHT_TD_INFO: + return "IGVM_VHT_TD_INFO" case IGVM_VHT_PARAMETER_AREA: return "IGVM_VHT_PARAMETER_AREA"; case IGVM_VHT_PAGE_DATA: @@ -163,6 +165,12 @@ static void igvm_dump_variable_header(IGVM_VHS_VARIABLE_HEADER *header) printf(" UsedSize: %016lX\n", vhs->used_size); break; } + case IGVM_VHT_TD_INFO: { + IGVM_VHS_TD_INFO *vhs = + (IGVM_VHS_TD_INFO *)vh_data; + printf(" CompatibilityMask: %08X\n", vhs->compatibility_mask); + printf(" XFAM: %016lX\n", vhs->xfam); + } case IGVM_VHT_PARAMETER_AREA: { IGVM_VHS_PARAMETER_AREA *vhs = (IGVM_VHS_PARAMETER_AREA *)vh_data; diff --git a/igvm_defs/src/lib.rs b/igvm_defs/src/lib.rs index a7aac9c..44cc882 100644 --- a/igvm_defs/src/lib.rs +++ b/igvm_defs/src/lib.rs @@ -658,8 +658,12 @@ pub struct IGVM_VHS_PAGE_TABLE_RELOCATION { /// /// Only supported on TDX platforms. #[repr(C)] -#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, PartialEq, Eq)] pub struct IGVM_VHS_TD_INFO { + /// Compatibility mask. + pub compatibility_mask: u32, + /// Reserved, must be zero. + pub reserved: u32, /// XFAM for CPU extended features setting. pub xfam: u64, } From 4684aff9f1fa9a5ce50cb6b76e78045689f4508b Mon Sep 17 00:00:00 2001 From: Alice Chen Date: Tue, 27 Jan 2026 11:50:08 -0800 Subject: [PATCH 4/9] format fixes --- igvm/src/lib.rs | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/igvm/src/lib.rs b/igvm/src/lib.rs index 4182ca7..60c198c 100644 --- a/igvm/src/lib.rs +++ b/igvm/src/lib.rs @@ -345,10 +345,7 @@ pub enum IgvmInitializationHeader { vtl: Vtl, }, /// Represents an [IGVM_VHS_TD_INFO]. - TdInfo { - compatibility_mask: u32, - xfam: u64, - }, + TdInfo { compatibility_mask: u32, xfam: u64 }, } impl IgvmInitializationHeader { @@ -362,9 +359,7 @@ impl IgvmInitializationHeader { IgvmInitializationHeader::PageTableRelocationRegion { .. } => { size_of::() } - IgvmInitializationHeader::TdInfo { .. } => { - size_of::() - } + IgvmInitializationHeader::TdInfo { .. } => size_of::(), }; size_of::() + additional @@ -384,9 +379,7 @@ impl IgvmInitializationHeader { IgvmInitializationHeader::PageTableRelocationRegion { .. } => { IgvmVariableHeaderType::IGVM_VHT_PAGE_TABLE_RELOCATION_REGION } - IgvmInitializationHeader::TdInfo { .. } => { - IgvmVariableHeaderType::IGVM_VHT_TD_INFO - } + IgvmInitializationHeader::TdInfo { .. } => IgvmVariableHeaderType::IGVM_VHT_TD_INFO, } } @@ -468,9 +461,7 @@ impl IgvmInitializationHeader { IgvmInitializationHeader::TdInfo { compatibility_mask: _, xfam: _, - } => { - Ok(()) - } + } => Ok(()), } } @@ -567,9 +558,7 @@ impl IgvmInitializationHeader { vtl: vtl.try_into().map_err(|_| BinaryHeaderError::InvalidVtl)?, } } - IgvmVariableHeaderType::IGVM_VHT_TD_INFO - if length == size_of::() => - { + IgvmVariableHeaderType::IGVM_VHT_TD_INFO if length == size_of::() => { let IGVM_VHS_TD_INFO { compatibility_mask, reserved, @@ -710,7 +699,7 @@ impl IgvmInitializationHeader { let info = IGVM_VHS_TD_INFO { compatibility_mask: *compatibility_mask, reserved: 0, - xfam: *xfam + xfam: *xfam, }; append_header( From 7a864a6aa644bddef5ea9e1f3cf08ca1d0ac2a0d Mon Sep 17 00:00:00 2001 From: Alice Chen Date: Tue, 27 Jan 2026 13:47:55 -0800 Subject: [PATCH 5/9] fix c build errs --- igvm_c/sample/dump_igvm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/igvm_c/sample/dump_igvm.c b/igvm_c/sample/dump_igvm.c index 1cb2049..b0092f8 100644 --- a/igvm_c/sample/dump_igvm.c +++ b/igvm_c/sample/dump_igvm.c @@ -62,7 +62,7 @@ static char *igvm_type_to_text(uint32_t type) case IGVM_VHT_PAGE_TABLE_RELOCATION_REGION: return "IGVM_VHT_PAGE_TABLE_RELOCATION_REGION"; case IGVM_VHT_TD_INFO: - return "IGVM_VHT_TD_INFO" + return "IGVM_VHT_TD_INFO"; case IGVM_VHT_PARAMETER_AREA: return "IGVM_VHT_PARAMETER_AREA"; case IGVM_VHT_PAGE_DATA: @@ -170,6 +170,7 @@ static void igvm_dump_variable_header(IGVM_VHS_VARIABLE_HEADER *header) (IGVM_VHS_TD_INFO *)vh_data; printf(" CompatibilityMask: %08X\n", vhs->compatibility_mask); printf(" XFAM: %016lX\n", vhs->xfam); + break; } case IGVM_VHT_PARAMETER_AREA: { IGVM_VHS_PARAMETER_AREA *vhs = From 378acf192bc795de49e6c719c7a7507ed7506671 Mon Sep 17 00:00:00 2001 From: Alice Chen Date: Wed, 28 Jan 2026 14:48:18 -0800 Subject: [PATCH 6/9] add validation and test that td_info is specific to TDX --- igvm/src/lib.rs | 77 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 9 deletions(-) diff --git a/igvm/src/lib.rs b/igvm/src/lib.rs index 60c198c..1057d18 100644 --- a/igvm/src/lib.rs +++ b/igvm/src/lib.rs @@ -2391,6 +2391,7 @@ impl IgvmFile { fn validate_platform_headers<'a>( revision: IgvmRevision, platform_headers: impl Iterator, + platform_types: &mut Vec, ) -> Result<(), Error> { let mut at_least_one = false; let mut isolation_types = HashMap::new(); @@ -2428,6 +2429,7 @@ impl IgvmFile { ); return Err(Error::MultiplePlatformHeadersWithSameIsolation); } + platform_types.push(info.platform_type); } } } @@ -2444,6 +2446,7 @@ impl IgvmFile { /// Returns additional info used to validate directive headers. fn validate_initialization_headers( revision: IgvmRevision, + platform_types: &[IgvmPlatformType], initialization_headers: &[IgvmInitializationHeader], ) -> Result { let mut page_table_masks = 0; @@ -2550,6 +2553,15 @@ impl IgvmFile { vtl: *vtl, }) } + IgvmInitializationHeader::TdInfo { + compatibility_mask: _, + xfam: _, + } => { + if !platform_types.contains(&IgvmPlatformType::TDX) || platform_types.len() != 1 + { + return Err(Error::InvalidPlatformType); + } + } // TODO: validate SNP policy compatibility mask specifies SNP _ => {} } @@ -2708,7 +2720,11 @@ impl IgvmFile { /// Serialize this IGVM file into the binary format, into the supplied /// output Vec. pub fn serialize(&self, output: &mut Vec) -> Result<(), Error> { - IgvmFile::validate_platform_headers(self.revision, self.platform_headers.iter())?; + IgvmFile::validate_platform_headers( + self.revision, + self.platform_headers.iter(), + &mut Vec::new(), + )?; // Build the variable header and file data section by looping through each header type. // First, calculate the starting data file offset relative to the rest of the file. @@ -2835,9 +2851,13 @@ impl IgvmFile { return Err(Error::UnsupportedPageSize(revision.page_size() as u32)); } - Self::validate_platform_headers(revision, platform_headers.iter())?; - let validation_info = - Self::validate_initialization_headers(revision, &initialization_headers)?; + let mut platform_types = Vec::new(); + Self::validate_platform_headers(revision, platform_headers.iter(), &mut platform_types)?; + let validation_info = Self::validate_initialization_headers( + revision, + &platform_types, + &initialization_headers, + )?; Self::validate_directive_headers(revision, &directive_headers, validation_info)?; Ok(Self { @@ -3202,21 +3222,29 @@ impl IgvmFile { // Validate the combination of both is valid. #[cfg(debug_assertions)] { + let mut self_platform_types = Vec::new(); debug_assert!(Self::validate_platform_headers( self.revision, - self.platform_headers.iter() + self.platform_headers.iter(), + &mut self_platform_types ) .is_ok()); + let mut other_platform_types = Vec::new(); debug_assert!(Self::validate_platform_headers( other.revision, - other.platform_headers.iter() + other.platform_headers.iter(), + &mut other_platform_types ) .is_ok()); - let self_info = - Self::validate_initialization_headers(self.revision, &self.initialization_headers) - .expect("valid file"); + let self_info = Self::validate_initialization_headers( + self.revision, + &self_platform_types, + &self.initialization_headers, + ) + .expect("valid file"); let other_info = Self::validate_initialization_headers( other.revision, + &other_platform_types, &other.initialization_headers, ) .expect("valid file"); @@ -3243,6 +3271,7 @@ impl IgvmFile { self.platform_headers .iter() .chain(other.platform_headers.iter()), + &mut Vec::new(), )?; // Check the platform headers for each file to see if they need to be @@ -4042,6 +4071,36 @@ mod tests { // // test headers equivalent function + #[test] + fn test_td_info_validation() { + // Test that creating an IgvmFile with a TdInfo header but without a TDX + // platform fails. + let file = IgvmFile::new( + IgvmRevision::V1, + vec![new_platform(0x1, IgvmPlatformType::VSM_ISOLATION)], + vec![IgvmInitializationHeader::TdInfo { + compatibility_mask: 0x1, + xfam: 0x00000000000618e7, + }], + vec![], + ); + assert!(file.is_err()); + assert!(matches!(file.err().unwrap(), Error::InvalidPlatformType,)); + + // Test that creating an IgvmFile with a TdInfo header and a TDX + // platform succeeds. + let file = IgvmFile::new( + IgvmRevision::V1, + vec![new_platform(0x1, IgvmPlatformType::TDX)], + vec![IgvmInitializationHeader::TdInfo { + compatibility_mask: 0x1, + xfam: 0, + }], + vec![], + ); + assert!(file.is_ok()); + } + /// Test a variable header matches the supplied args. Also tests that the header deserialized returns the original /// header. fn test_variable_header( From 3bc54cfec79ce193a3a649de5549e478b7436931 Mon Sep 17 00:00:00 2001 From: Alice Chen Date: Wed, 28 Jan 2026 15:26:54 -0800 Subject: [PATCH 7/9] Revert "add validation and test that td_info is specific to TDX" This reverts commit 378acf192bc795de49e6c719c7a7507ed7506671. --- igvm/src/lib.rs | 77 ++++++------------------------------------------- 1 file changed, 9 insertions(+), 68 deletions(-) diff --git a/igvm/src/lib.rs b/igvm/src/lib.rs index 1057d18..60c198c 100644 --- a/igvm/src/lib.rs +++ b/igvm/src/lib.rs @@ -2391,7 +2391,6 @@ impl IgvmFile { fn validate_platform_headers<'a>( revision: IgvmRevision, platform_headers: impl Iterator, - platform_types: &mut Vec, ) -> Result<(), Error> { let mut at_least_one = false; let mut isolation_types = HashMap::new(); @@ -2429,7 +2428,6 @@ impl IgvmFile { ); return Err(Error::MultiplePlatformHeadersWithSameIsolation); } - platform_types.push(info.platform_type); } } } @@ -2446,7 +2444,6 @@ impl IgvmFile { /// Returns additional info used to validate directive headers. fn validate_initialization_headers( revision: IgvmRevision, - platform_types: &[IgvmPlatformType], initialization_headers: &[IgvmInitializationHeader], ) -> Result { let mut page_table_masks = 0; @@ -2553,15 +2550,6 @@ impl IgvmFile { vtl: *vtl, }) } - IgvmInitializationHeader::TdInfo { - compatibility_mask: _, - xfam: _, - } => { - if !platform_types.contains(&IgvmPlatformType::TDX) || platform_types.len() != 1 - { - return Err(Error::InvalidPlatformType); - } - } // TODO: validate SNP policy compatibility mask specifies SNP _ => {} } @@ -2720,11 +2708,7 @@ impl IgvmFile { /// Serialize this IGVM file into the binary format, into the supplied /// output Vec. pub fn serialize(&self, output: &mut Vec) -> Result<(), Error> { - IgvmFile::validate_platform_headers( - self.revision, - self.platform_headers.iter(), - &mut Vec::new(), - )?; + IgvmFile::validate_platform_headers(self.revision, self.platform_headers.iter())?; // Build the variable header and file data section by looping through each header type. // First, calculate the starting data file offset relative to the rest of the file. @@ -2851,13 +2835,9 @@ impl IgvmFile { return Err(Error::UnsupportedPageSize(revision.page_size() as u32)); } - let mut platform_types = Vec::new(); - Self::validate_platform_headers(revision, platform_headers.iter(), &mut platform_types)?; - let validation_info = Self::validate_initialization_headers( - revision, - &platform_types, - &initialization_headers, - )?; + Self::validate_platform_headers(revision, platform_headers.iter())?; + let validation_info = + Self::validate_initialization_headers(revision, &initialization_headers)?; Self::validate_directive_headers(revision, &directive_headers, validation_info)?; Ok(Self { @@ -3222,29 +3202,21 @@ impl IgvmFile { // Validate the combination of both is valid. #[cfg(debug_assertions)] { - let mut self_platform_types = Vec::new(); debug_assert!(Self::validate_platform_headers( self.revision, - self.platform_headers.iter(), - &mut self_platform_types + self.platform_headers.iter() ) .is_ok()); - let mut other_platform_types = Vec::new(); debug_assert!(Self::validate_platform_headers( other.revision, - other.platform_headers.iter(), - &mut other_platform_types + other.platform_headers.iter() ) .is_ok()); - let self_info = Self::validate_initialization_headers( - self.revision, - &self_platform_types, - &self.initialization_headers, - ) - .expect("valid file"); + let self_info = + Self::validate_initialization_headers(self.revision, &self.initialization_headers) + .expect("valid file"); let other_info = Self::validate_initialization_headers( other.revision, - &other_platform_types, &other.initialization_headers, ) .expect("valid file"); @@ -3271,7 +3243,6 @@ impl IgvmFile { self.platform_headers .iter() .chain(other.platform_headers.iter()), - &mut Vec::new(), )?; // Check the platform headers for each file to see if they need to be @@ -4071,36 +4042,6 @@ mod tests { // // test headers equivalent function - #[test] - fn test_td_info_validation() { - // Test that creating an IgvmFile with a TdInfo header but without a TDX - // platform fails. - let file = IgvmFile::new( - IgvmRevision::V1, - vec![new_platform(0x1, IgvmPlatformType::VSM_ISOLATION)], - vec![IgvmInitializationHeader::TdInfo { - compatibility_mask: 0x1, - xfam: 0x00000000000618e7, - }], - vec![], - ); - assert!(file.is_err()); - assert!(matches!(file.err().unwrap(), Error::InvalidPlatformType,)); - - // Test that creating an IgvmFile with a TdInfo header and a TDX - // platform succeeds. - let file = IgvmFile::new( - IgvmRevision::V1, - vec![new_platform(0x1, IgvmPlatformType::TDX)], - vec![IgvmInitializationHeader::TdInfo { - compatibility_mask: 0x1, - xfam: 0, - }], - vec![], - ); - assert!(file.is_ok()); - } - /// Test a variable header matches the supplied args. Also tests that the header deserialized returns the original /// header. fn test_variable_header( From df11e6064984819cb2c3a7415b1c7b6c970bcf94 Mon Sep 17 00:00:00 2001 From: Alice Chen Date: Wed, 28 Jan 2026 16:45:32 -0800 Subject: [PATCH 8/9] change method for checking supported platform --- igvm/src/lib.rs | 80 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/igvm/src/lib.rs b/igvm/src/lib.rs index 60c198c..a91b666 100644 --- a/igvm/src/lib.rs +++ b/igvm/src/lib.rs @@ -2391,7 +2391,7 @@ impl IgvmFile { fn validate_platform_headers<'a>( revision: IgvmRevision, platform_headers: impl Iterator, - ) -> Result<(), Error> { + ) -> Result, Error> { let mut at_least_one = false; let mut isolation_types = HashMap::new(); @@ -2435,7 +2435,7 @@ impl IgvmFile { if !at_least_one { Err(Error::NoPlatformHeaders) } else { - Ok(()) + Ok(isolation_types) } } @@ -2445,6 +2445,7 @@ impl IgvmFile { fn validate_initialization_headers( revision: IgvmRevision, initialization_headers: &[IgvmInitializationHeader], + isolation_types: HashMap, ) -> Result { let mut page_table_masks = 0; let mut used_vp_idents: Vec = Vec::new(); @@ -2550,6 +2551,20 @@ impl IgvmFile { vtl: *vtl, }) } + IgvmInitializationHeader::TdInfo { + compatibility_mask, + xfam: _, + } => { + if !isolation_types.contains_key(&IgvmPlatformType::TDX) + || isolation_types + .get(&IgvmPlatformType::TDX) + .unwrap() + .compatibility_mask + != *compatibility_mask + { + return Err(Error::InvalidPlatformType); + } + } // TODO: validate SNP policy compatibility mask specifies SNP _ => {} } @@ -2835,9 +2850,12 @@ impl IgvmFile { return Err(Error::UnsupportedPageSize(revision.page_size() as u32)); } - Self::validate_platform_headers(revision, platform_headers.iter())?; - let validation_info = - Self::validate_initialization_headers(revision, &initialization_headers)?; + let isolation_types = Self::validate_platform_headers(revision, platform_headers.iter())?; + let validation_info = Self::validate_initialization_headers( + revision, + &initialization_headers, + isolation_types, + )?; Self::validate_directive_headers(revision, &directive_headers, validation_info)?; Ok(Self { @@ -3202,22 +3220,22 @@ impl IgvmFile { // Validate the combination of both is valid. #[cfg(debug_assertions)] { - debug_assert!(Self::validate_platform_headers( + let self_isolation_types = + Self::validate_platform_headers(self.revision, self.platform_headers.iter()) + .expect("valid file"); + let other_isolation_types = + Self::validate_platform_headers(other.revision, other.platform_headers.iter()) + .expect("valid file"); + let self_info = Self::validate_initialization_headers( self.revision, - self.platform_headers.iter() + &self.initialization_headers, + self_isolation_types, ) - .is_ok()); - debug_assert!(Self::validate_platform_headers( - other.revision, - other.platform_headers.iter() - ) - .is_ok()); - let self_info = - Self::validate_initialization_headers(self.revision, &self.initialization_headers) - .expect("valid file"); + .expect("valid file"); let other_info = Self::validate_initialization_headers( other.revision, &other.initialization_headers, + other_isolation_types, ) .expect("valid file"); debug_assert!(Self::validate_directive_headers( @@ -4042,6 +4060,36 @@ mod tests { // // test headers equivalent function + #[test] + fn test_td_info_validation() { + // Test that creating an IgvmFile with a TdInfo header but without a TDX + // platform fails. + let file = IgvmFile::new( + IgvmRevision::V1, + vec![new_platform(0x1, IgvmPlatformType::VSM_ISOLATION)], + vec![IgvmInitializationHeader::TdInfo { + compatibility_mask: 0x1, + xfam: 0x00000000000618e7, + }], + vec![], + ); + assert!(file.is_err()); + assert!(matches!(file.err().unwrap(), Error::InvalidPlatformType,)); + + // Test that creating an IgvmFile with a TdInfo header and a TDX + // platform succeeds. + let file = IgvmFile::new( + IgvmRevision::V1, + vec![new_platform(0x1, IgvmPlatformType::TDX)], + vec![IgvmInitializationHeader::TdInfo { + compatibility_mask: 0x1, + xfam: 0, + }], + vec![], + ); + assert!(file.is_ok()); + } + /// Test a variable header matches the supplied args. Also tests that the header deserialized returns the original /// header. fn test_variable_header( From a51d9721f735546c0aad150ad8cd8ea6edb3e4bb Mon Sep 17 00:00:00 2001 From: Alice Chen Date: Thu, 29 Jan 2026 15:48:33 -0800 Subject: [PATCH 9/9] fix comments --- igvm_defs/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/igvm_defs/src/lib.rs b/igvm_defs/src/lib.rs index 44cc882..8fb09d7 100644 --- a/igvm_defs/src/lib.rs +++ b/igvm_defs/src/lib.rs @@ -653,8 +653,8 @@ pub struct IGVM_VHS_PAGE_TABLE_RELOCATION { /// /// The XFAM (Extended Features Allowed Mask) value specifies a mask of CPU extended features /// that the TD is allowed to use. If the XFAM value is invalid or not supported by the host, -/// the igvm file will fail to load. If the host overrides the specified XFAM value, -/// attestation will fail. +/// the host should fail to load the IGVM file. This value is reflected in attestation +/// measurement. /// /// Only supported on TDX platforms. #[repr(C)]