Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 110 additions & 16 deletions igvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@ pub enum IgvmInitializationHeader {
vp_index: u16,
vtl: Vtl,
},
/// Represents an [IGVM_VHS_TD_INFO].
TdInfo { compatibility_mask: u32, xfam: u64 },
}

impl IgvmInitializationHeader {
Expand All @@ -357,6 +359,7 @@ impl IgvmInitializationHeader {
IgvmInitializationHeader::PageTableRelocationRegion { .. } => {
size_of::<IGVM_VHS_PAGE_TABLE_RELOCATION>()
}
IgvmInitializationHeader::TdInfo { .. } => size_of::<IGVM_VHS_TD_INFO>(),
};

size_of::<IGVM_VHS_VARIABLE_HEADER>() + additional
Expand All @@ -376,6 +379,7 @@ impl IgvmInitializationHeader {
IgvmInitializationHeader::PageTableRelocationRegion { .. } => {
IgvmVariableHeaderType::IGVM_VHT_PAGE_TABLE_RELOCATION_REGION
}
IgvmInitializationHeader::TdInfo { .. } => IgvmVariableHeaderType::IGVM_VHT_TD_INFO,
}
}

Expand Down Expand Up @@ -454,6 +458,10 @@ impl IgvmInitializationHeader {

Ok(())
}
IgvmInitializationHeader::TdInfo {
compatibility_mask: _,
xfam: _,
} => Ok(()),
}
}

Expand Down Expand Up @@ -550,6 +558,22 @@ impl IgvmInitializationHeader {
vtl: vtl.try_into().map_err(|_| BinaryHeaderError::InvalidVtl)?,
}
}
IgvmVariableHeaderType::IGVM_VHT_TD_INFO if length == size_of::<IGVM_VHS_TD_INFO>() => {
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),
};
Expand All @@ -572,6 +596,9 @@ impl IgvmInitializationHeader {
PageTableRelocationRegion {
compatibility_mask, ..
} => Some(*compatibility_mask),
TdInfo {
compatibility_mask, ..
} => Some(*compatibility_mask),
}
}

Expand Down Expand Up @@ -665,6 +692,22 @@ impl IgvmInitializationHeader {
variable_headers,
);
}
IgvmInitializationHeader::TdInfo {
compatibility_mask,
xfam,
} => {
let info = IGVM_VHS_TD_INFO {
compatibility_mask: *compatibility_mask,
reserved: 0,
xfam: *xfam,
};

append_header(
&info,
IgvmVariableHeaderType::IGVM_VHT_TD_INFO,
variable_headers,
);
}
}

Ok(())
Expand Down Expand Up @@ -2348,7 +2391,7 @@ impl IgvmFile {
fn validate_platform_headers<'a>(
revision: IgvmRevision,
platform_headers: impl Iterator<Item = &'a IgvmPlatformHeader>,
) -> Result<(), Error> {
) -> Result<HashMap<IgvmPlatformType, &'a IGVM_VHS_SUPPORTED_PLATFORM>, Error> {
let mut at_least_one = false;
let mut isolation_types = HashMap::new();

Expand Down Expand Up @@ -2392,7 +2435,7 @@ impl IgvmFile {
if !at_least_one {
Err(Error::NoPlatformHeaders)
} else {
Ok(())
Ok(isolation_types)
}
}

Expand All @@ -2402,6 +2445,7 @@ impl IgvmFile {
fn validate_initialization_headers(
revision: IgvmRevision,
initialization_headers: &[IgvmInitializationHeader],
isolation_types: HashMap<IgvmPlatformType, &IGVM_VHS_SUPPORTED_PLATFORM>,
) -> Result<DirectiveHeaderValidationInfo, Error> {
let mut page_table_masks = 0;
let mut used_vp_idents: Vec<VpIdentifier> = Vec::new();
Expand Down Expand Up @@ -2507,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
_ => {}
}
Expand Down Expand Up @@ -2792,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 {
Expand Down Expand Up @@ -3159,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()
)
.is_ok());
debug_assert!(Self::validate_platform_headers(
other.revision,
other.platform_headers.iter()
&self.initialization_headers,
self_isolation_types,
)
.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(
Expand Down Expand Up @@ -3329,6 +3390,9 @@ impl IgvmFile {
IgvmInitializationHeader::PageTableRelocationRegion {
compatibility_mask, ..
} => fixup_mask(compatibility_mask),
IgvmInitializationHeader::TdInfo {
compatibility_mask, ..
} => fixup_mask(compatibility_mask),
}
}

Expand Down Expand Up @@ -3996,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<T: IntoBytes + Immutable + KnownLayout>(
Expand Down
49 changes: 25 additions & 24 deletions igvm_c/cbindgen_igvm_defs.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
language = "C"

header = """
/*
/*
* SPDX-License-Identifier: MIT OR Apache-2.0
*
* Copyright (c) 2023 SUSE LLC
Expand Down Expand Up @@ -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"]
Expand Down
11 changes: 10 additions & 1 deletion igvm_c/sample/dump_igvm.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
* SPDX-License-Identifier: MIT OR Apache-2.0
*
* Copyright (c) 2023 SUSE LLC
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -163,6 +165,13 @@ 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);
break;
}
case IGVM_VHT_PARAMETER_AREA: {
IGVM_VHS_PARAMETER_AREA *vhs =
(IGVM_VHS_PARAMETER_AREA *)vh_data;
Expand Down
22 changes: 22 additions & 0 deletions igvm_defs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
/// TDX launch time configurations as 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`].
Expand Down Expand Up @@ -646,6 +649,25 @@ 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.
#[repr(C)]
#[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,
}

/// 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
Expand Down