From c13f0486b32f550db0922595e52b663e5dea3764 Mon Sep 17 00:00:00 2001 From: "alex.lyn" Date: Sun, 13 Jul 2025 20:40:55 +0800 Subject: [PATCH 1/5] runtime-rs: Add protection device and payload configuration Introduces `ProtectionDevConfig` and `mrconfigid` fields to support CoCo/InitData feature in Cloud Hypervisor. This change enables the runtime-rs/cloud-hypervisor to: - Configure and manage 'protection devices' associated with hypervisor instances (Specially when the CVM starts). - Include 'MRCONFIGID' in the payload configuration, allowing integrity verification via initdata of the VM's payload within TEEs. This is a foundational step towards robust CVM support, enhancing the trustworthiness and integrity verification with initdata inside TEE platforms. Signed-off-by: alex.lyn --- src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs | 1 + src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs | 8 ++++++++ .../crates/hypervisor/src/ch/inner_hypervisor.rs | 1 + 3 files changed, 10 insertions(+) diff --git a/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs b/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs index cd6998a649..61bc1c7e43 100644 --- a/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs +++ b/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs @@ -424,6 +424,7 @@ impl TryFrom<(BootInfo, Option, GuestProtection)> for PayloadConfig { initramfs, cmdline, firmware, + mrconfigid: None, }; Ok(payload) diff --git a/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs b/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs index 8b6dfa69ca..3cf0c81541 100644 --- a/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs +++ b/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs @@ -229,6 +229,11 @@ pub struct MemoryZoneConfig { pub prefault: bool, } +#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)] +pub struct ProtectionDevConfig { + pub mrconfigid: Option, +} + #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub struct NetConfig { //#[serde(default = "default_netconfig_tap")] @@ -330,6 +335,8 @@ pub struct PayloadConfig { pub cmdline: Option, #[serde(default)] pub initramfs: Option, + #[serde(default)] + pub mrconfigid: Option, } #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] @@ -510,6 +517,7 @@ pub struct NamedHypervisorConfig { // - The hardware supports guest protection. // - The user has requested that guest protection be used. pub guest_protection_to_use: GuestProtection, + pub protection_device: Option, } #[derive(Clone, Debug, Deserialize, Serialize, Default)] diff --git a/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs b/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs index 68146b6b4c..b24eeda0d7 100644 --- a/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs +++ b/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs @@ -217,6 +217,7 @@ impl CloudHypervisorInner { guest_protection_to_use: self.guest_protection_to_use.clone(), shared_fs_devices, host_devices, + protection_device: None, ..Default::default() }; From e6fff6f145bfaf7a9bde69fd952124eeb7382df0 Mon Sep 17 00:00:00 2001 From: "alex.lyn" Date: Sun, 13 Jul 2025 21:03:28 +0800 Subject: [PATCH 2/5] runtime-rs: Pass protection device config to payload conversion This commit implements the conversion logic for the newly introduced CoCo/Initdata configurations, ensuring that `ProtectionDevConfig` data, particularly the `mrconfigid`, is correctly passed. And the main Changes are as below: - Importing `ProtectionDevConfig` for use in conversion logic. - Extracting `protection_device` from `NamedHypervisorConfig` and passing it during the conversion to `VmConfig`. - Updating the `TryFrom` implementation for `PayloadConfig` to accept the `ProtectionDevConfig` and use its `mrconfigid` to populate the `PayloadConfig`'s `mrconfigid` field. - Adjusting unit tests to reflect the updated `PayloadConfig` conversion signature and `mrconfigid` handling. Signed-off-by: alex.lyn --- .../hypervisor/ch-config/src/convert.rs | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs b/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs index 61bc1c7e43..4026d5dadf 100644 --- a/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs +++ b/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::NamedHypervisorConfig; +use crate::ProtectionDevConfig; use crate::VmConfig; use crate::{ guest_protection_is_tdx, ConsoleConfig, ConsoleOutputMode, CpuFeatures, CpuTopology, @@ -110,6 +111,7 @@ impl TryFrom for VmConfig { let fs = n.shared_fs_devices; let net = n.network_devices; let host_devices = n.host_devices; + let protection_dev = n.protection_device; let cpus = CpusConfig::try_from((cfg.cpu_info, guest_protection_to_use.clone())) .map_err(VmConfigError::CPUError)?; @@ -143,6 +145,7 @@ impl TryFrom for VmConfig { boot_info.clone(), kernel_params, guest_protection_to_use.clone(), + protection_dev, )) .map_err(VmConfigError::PayloadError)?, ); @@ -385,13 +388,28 @@ impl From for CpuFeatures { // // - The 3rd tuple element determines if TDX is enabled. // -impl TryFrom<(BootInfo, Option, GuestProtection)> for PayloadConfig { +impl + TryFrom<( + BootInfo, + Option, + GuestProtection, + Option, + )> for PayloadConfig +{ type Error = PayloadConfigError; - fn try_from(args: (BootInfo, Option, GuestProtection)) -> Result { + fn try_from( + args: ( + BootInfo, + Option, + GuestProtection, + Option, + ), + ) -> Result { let boot_info = args.0; let cmdline = args.1; let guest_protection_to_use = args.2; + let protection_device = args.3; // The kernel is always specified here, // not in the top level VmConfig.kernel. @@ -419,12 +437,18 @@ impl TryFrom<(BootInfo, Option, GuestProtection)> for PayloadConfig { Some(PathBuf::from(boot_info.firmware)) }; + let mrconfigid = if let Some(data) = protection_device { + data.mrconfigid + } else { + None + }; + let payload = PayloadConfig { kernel: Some(kernel), initramfs, cmdline, firmware, - mrconfigid: None, + mrconfigid, }; Ok(payload) @@ -696,6 +720,7 @@ mod tests { initramfs: Some(PathBuf::from(initramfs)), firmware: payload_firmware, cmdline, + mrconfigid: None, }; (boot_info, payload_config) @@ -1273,6 +1298,7 @@ mod tests { boot_info: BootInfo, cmdline: Option, guest_protection: GuestProtection, + protection_device: Option, result: Result, } @@ -1309,6 +1335,7 @@ mod tests { boot_info: BootInfo::default(), cmdline: None, guest_protection: GuestProtection::NoProtection, + protection_device: None, result: Err(PayloadConfigError::NoKernel), }, TestData { @@ -1321,6 +1348,7 @@ mod tests { }, cmdline: None, guest_protection: GuestProtection::NoProtection, + protection_device: None, result: Ok(PayloadConfig { kernel: Some(PathBuf::from(kernel)), cmdline: None, @@ -1340,11 +1368,13 @@ mod tests { }, cmdline: None, guest_protection: GuestProtection::NoProtection, + protection_device: None, result: Ok(PayloadConfig { kernel: Some(PathBuf::from(kernel)), cmdline: None, initramfs: Some(PathBuf::from(initramfs)), firmware: Some(PathBuf::from(firmware)), + mrconfigid: None, }), }, TestData { @@ -1357,6 +1387,7 @@ mod tests { }, cmdline: Some(cmdline.to_string()), guest_protection: GuestProtection::NoProtection, + protection_device: None, result: Ok(PayloadConfig { kernel: Some(PathBuf::from(kernel)), initramfs: Some(PathBuf::from(initramfs)), @@ -1374,18 +1405,21 @@ mod tests { }, cmdline: None, guest_protection: GuestProtection::Tdx, + protection_device: None, result: Err(PayloadConfigError::TDXFirmwareMissing), }, TestData { boot_info: boot_info_with_initrd, cmdline: Some(cmdline.to_string()), guest_protection: GuestProtection::Tdx, + protection_device: None, result: Ok(payload_config_with_initrd), }, TestData { boot_info: boot_info_without_initrd, cmdline: Some(cmdline.to_string()), guest_protection: GuestProtection::Tdx, + protection_device: None, result: Ok(payload_config_without_initrd), }, ]; @@ -1397,6 +1431,7 @@ mod tests { d.boot_info.clone(), d.cmdline.clone(), d.guest_protection.clone(), + d.protection_device.clone(), )); let msg = format!("{}: actual result: {:?}", msg, result); From 6dde0a91cac736342a4d882eb4879b6e3047c7ef Mon Sep 17 00:00:00 2001 From: "alex.lyn" Date: Sun, 13 Jul 2025 21:16:12 +0800 Subject: [PATCH 3/5] runtime-rs: Process CoCo protection devices for InitData This commit extends the Cloud Hypervisor integration within `runtime-rs` to correctly process and extract CoCo related device configurations. Specifically, it includes: - Adds handling for `DeviceType::Protection` to `add_device`, allowing these devices to be queued for processing. - Retrieve the pending device list, identify and extract `ProtectionDevConfig` and implements the logic to handle the `mrconfigid` from protection device. This ensures that initdata related prameters are properly consumed by the runtime and made it available for Cloud Hypervisor to utilize during the setup of CVM. Signed-off-by: alex.lyn --- .../crates/hypervisor/src/ch/inner_device.rs | 24 ++++++++++++++++++- .../hypervisor/src/ch/inner_hypervisor.rs | 3 ++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs b/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs index 7ef5fd7dad..ee4c0613be 100644 --- a/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs +++ b/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs @@ -13,6 +13,7 @@ use crate::utils::open_named_tuntap; use crate::HybridVsockDevice; use crate::NetworkConfig; use crate::NetworkDevice; +use crate::ProtectionDeviceConfig; use crate::ShareFsConfig; use crate::ShareFsDevice; use crate::VfioDevice; @@ -28,10 +29,13 @@ use ch_config::ch_api::{ use ch_config::convert::DEFAULT_NUM_PCI_SEGMENTS; use ch_config::DiskConfig; use ch_config::ImageType; -use ch_config::{net_util::MacAddr, DeviceConfig, FsConfig, NetConfig, VsockConfig}; +use ch_config::{ + net_util::MacAddr, DeviceConfig, FsConfig, NetConfig, ProtectionDevConfig, VsockConfig, +}; use kata_sys_util::netns::NetnsGuard; use kata_types::config::hypervisor::RateLimiterConfig; use kata_types::rootless::is_rootless; + use safe_path::scoped_join; use std::convert::TryFrom; use std::os::fd::AsRawFd; @@ -72,6 +76,7 @@ impl CloudHypervisorInner { DeviceType::ShareFs(_) => self.pending_devices.insert(0, device.clone()), DeviceType::Network(_) => self.pending_devices.insert(0, device.clone()), DeviceType::Vfio(_) => self.pending_devices.insert(0, device.clone()), + DeviceType::Protection(_) => self.pending_devices.insert(0, device.clone()), _ => { debug!( sl!(), @@ -404,10 +409,12 @@ impl CloudHypervisorInner { Option>, Option>, Option>, + Option, )> { let mut shared_fs_devices = Vec::::new(); let mut network_devices = Vec::::new(); let mut host_devices = Vec::::new(); + let mut protection_device = ProtectionDevConfig::default(); while let Some(dev) = self.pending_devices.pop() { match dev { @@ -512,6 +519,20 @@ impl CloudHypervisorInner { ); host_devices.push(device_config); } + DeviceType::Protection(pdev) => { + let config = pdev.config; + match config { + // ProtectionDeviceConfig::SevSnp(sevsnp_cfg) => { + // if sevsnp_cfg.is_snp { + // protection_device.host_data = sevsnp_cfg.host_data; + // } + // } + ProtectionDeviceConfig::Tdx(tdx_config) => { + protection_device.mrconfigid = tdx_config.mrconfigid; + } + _ => info!(sl!(), "CH: unsupported protection device type"), + } + } _ => continue, } } @@ -520,6 +541,7 @@ impl CloudHypervisorInner { Some(shared_fs_devices), Some(network_devices), Some(host_devices), + Some(protection_device), )) } } diff --git a/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs b/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs index b24eeda0d7..e5c8c10ce5 100644 --- a/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs +++ b/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs @@ -187,7 +187,8 @@ impl CloudHypervisorInner { } async fn boot_vm(&mut self) -> Result<()> { - let (shared_fs_devices, network_devices, host_devices) = self.get_shared_devices().await?; + let (shared_fs_devices, network_devices, host_devices, _) = + self.get_shared_devices().await?; let socket = self .api_socket .as_ref() From 7040c66d0754e4c5d5d9f0c598cdce09bb720275 Mon Sep 17 00:00:00 2001 From: "alex.lyn" Date: Sun, 13 Jul 2025 21:45:39 +0800 Subject: [PATCH 4/5] runtime-rs: Pass protection device config to VM boot This commit completes the integration of the protection device configuration into the Cloud Hypervisor VM boot process. Previously, the `protection_device` returned by `get_shared_devices()` was ignored. This change now correctly extracts the `protection_device` and passes it to the `VmConfig` creation during `boot_vm`. Signed-off-by: alex.lyn --- src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs b/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs index e5c8c10ce5..7a3a4bb013 100644 --- a/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs +++ b/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs @@ -187,8 +187,9 @@ impl CloudHypervisorInner { } async fn boot_vm(&mut self) -> Result<()> { - let (shared_fs_devices, network_devices, host_devices, _) = + let (shared_fs_devices, network_devices, host_devices, protection_device) = self.get_shared_devices().await?; + let socket = self .api_socket .as_ref() @@ -218,7 +219,7 @@ impl CloudHypervisorInner { guest_protection_to_use: self.guest_protection_to_use.clone(), shared_fs_devices, host_devices, - protection_device: None, + protection_device, ..Default::default() }; From d88d7faf4c43f5390b2dfb08ee5452ff0b773021 Mon Sep 17 00:00:00 2001 From: Alex Lyn Date: Tue, 7 Apr 2026 10:30:36 +0800 Subject: [PATCH 5/5] runtime-rs: Add support SEV-SNP host data in Clh This commit aims to add support SEV-SNP host data within cloud-hypervisor, which will help pass down the initdata coming from upper layer. In SEV-SNP cases, with it enabled, the Cloud-hypervisor will receive host-data string, otherwise it's set default None. Signed-off-by: Alex Lyn --- .../crates/hypervisor/ch-config/src/convert.rs | 13 +++++++++++-- .../crates/hypervisor/ch-config/src/lib.rs | 3 +++ .../crates/hypervisor/src/ch/inner_device.rs | 10 +++++----- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs b/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs index 4026d5dadf..4d35292262 100644 --- a/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs +++ b/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs @@ -437,8 +437,14 @@ impl Some(PathBuf::from(boot_info.firmware)) }; - let mrconfigid = if let Some(data) = protection_device { - data.mrconfigid + let mrconfigid = if let Some(ref data) = protection_device { + data.mrconfigid.clone() + } else { + None + }; + + let host_data = if let Some(ref data) = protection_device { + data.host_data.clone() } else { None }; @@ -449,6 +455,7 @@ impl cmdline, firmware, mrconfigid, + host_data, }; Ok(payload) @@ -721,6 +728,7 @@ mod tests { firmware: payload_firmware, cmdline, mrconfigid: None, + host_data: None, }; (boot_info, payload_config) @@ -1375,6 +1383,7 @@ mod tests { initramfs: Some(PathBuf::from(initramfs)), firmware: Some(PathBuf::from(firmware)), mrconfigid: None, + host_data: None, }), }, TestData { diff --git a/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs b/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs index 3cf0c81541..19b0489c4a 100644 --- a/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs +++ b/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs @@ -232,6 +232,7 @@ pub struct MemoryZoneConfig { #[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)] pub struct ProtectionDevConfig { pub mrconfigid: Option, + pub host_data: Option, } #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] @@ -337,6 +338,8 @@ pub struct PayloadConfig { pub initramfs: Option, #[serde(default)] pub mrconfigid: Option, + #[serde(default)] + pub host_data: Option, } #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)] diff --git a/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs b/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs index ee4c0613be..816b18bf7d 100644 --- a/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs +++ b/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs @@ -522,11 +522,11 @@ impl CloudHypervisorInner { DeviceType::Protection(pdev) => { let config = pdev.config; match config { - // ProtectionDeviceConfig::SevSnp(sevsnp_cfg) => { - // if sevsnp_cfg.is_snp { - // protection_device.host_data = sevsnp_cfg.host_data; - // } - // } + ProtectionDeviceConfig::SevSnp(sevsnp_cfg) => { + if sevsnp_cfg.is_snp { + protection_device.host_data = sevsnp_cfg.host_data; + } + } ProtectionDeviceConfig::Tdx(tdx_config) => { protection_device.mrconfigid = tdx_config.mrconfigid; }