From c5e560e2d11a23cc5385622436990d59adaf5a3e Mon Sep 17 00:00:00 2001 From: Pavel Mores Date: Thu, 30 Jan 2025 12:30:21 +0100 Subject: [PATCH] runtime-rs: handle ProtectionDevice in resource manager and sandbox As part of device preparation in Sandbox we check available protection and create a corresponding ProtectionDeviceConfig if appropriate. The resource-side handling is trivial. Signed-off-by: Pavel Mores --- src/runtime-rs/crates/resource/src/lib.rs | 3 +- .../crates/resource/src/manager_inner.rs | 5 ++ .../runtimes/virt_container/src/sandbox.rs | 69 +++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/runtime-rs/crates/resource/src/lib.rs b/src/runtime-rs/crates/resource/src/lib.rs index 413b1c6512..23669ccb0c 100644 --- a/src/runtime-rs/crates/resource/src/lib.rs +++ b/src/runtime-rs/crates/resource/src/lib.rs @@ -17,7 +17,7 @@ pub mod manager; mod manager_inner; pub mod network; pub mod resource_persist; -use hypervisor::{BlockConfig, HybridVsockConfig, VsockConfig}; +use hypervisor::{BlockConfig, HybridVsockConfig, ProtectionDeviceConfig, VsockConfig}; use network::NetworkConfig; pub mod rootfs; pub mod share_fs; @@ -35,6 +35,7 @@ pub enum ResourceConfig { VmRootfs(BlockConfig), HybridVsock(HybridVsockConfig), Vsock(VsockConfig), + Protection(ProtectionDeviceConfig), } #[derive(Debug, Clone, Copy, PartialEq)] diff --git a/src/runtime-rs/crates/resource/src/manager_inner.rs b/src/runtime-rs/crates/resource/src/manager_inner.rs index d2f2d24a3f..3bc818ed0f 100644 --- a/src/runtime-rs/crates/resource/src/manager_inner.rs +++ b/src/runtime-rs/crates/resource/src/manager_inner.rs @@ -146,6 +146,11 @@ impl ResourceManagerInner { .await .context("do handle vsock device failed.")?; } + ResourceConfig::Protection(p) => { + do_handle_device(&self.device_manager, &DeviceConfig::ProtectionDevCfg(p)) + .await + .context("do handle protection device failed.")?; + } }; } diff --git a/src/runtime-rs/crates/runtimes/virt_container/src/sandbox.rs b/src/runtime-rs/crates/runtimes/virt_container/src/sandbox.rs index 3e9b836e90..c95c87daa5 100644 --- a/src/runtime-rs/crates/runtimes/virt_container/src/sandbox.rs +++ b/src/runtime-rs/crates/runtimes/virt_container/src/sandbox.rs @@ -29,8 +29,11 @@ use hypervisor::{dragonball::Dragonball, HYPERVISOR_DRAGONBALL}; use hypervisor::{qemu::Qemu, HYPERVISOR_QEMU}; use hypervisor::{utils::get_hvsock_path, HybridVsockConfig, DEFAULT_GUEST_VSOCK_CID}; use hypervisor::{BlockConfig, Hypervisor}; +use hypervisor::{ProtectionDeviceConfig, SevSnpConfig}; use kata_sys_util::hooks::HookStates; +use kata_sys_util::protection::{available_guest_protection, GuestProtection}; use kata_types::capabilities::CapabilityBits; +use kata_types::config::hypervisor::Hypervisor as HypervisorConfig; #[cfg(not(target_arch = "s390x"))] use kata_types::config::hypervisor::HYPERVISOR_NAME_CH; use kata_types::config::TomlConfig; @@ -156,6 +159,15 @@ impl VirtSandbox { resource_configs.push(vm_rootfs); } + // prepare protection device config + if let Some(protection_dev_config) = self + .prepare_protection_device_config(&self.hypervisor.hypervisor_config().await) + .await + .context("failed to prepare protection device config")? + { + resource_configs.push(ResourceConfig::Protection(protection_dev_config)); + } + Ok(resource_configs) } @@ -302,6 +314,63 @@ impl VirtSandbox { Ok(vm_socket) } + async fn prepare_protection_device_config( + &self, + hypervisor_config: &HypervisorConfig, + ) -> Result> { + if !hypervisor_config.security_info.confidential_guest { + return Ok(None); + } + + let available_protection = available_guest_protection()?; + info!( + sl!(), + "sandbox: available protection: {:?}", available_protection + ); + + match available_protection { + GuestProtection::Sev(details) => { + if hypervisor_config.boot_info.firmware.is_empty() { + return Err(anyhow!("SEV protection requires a path to firmaware")); + } + + Ok(Some(ProtectionDeviceConfig::SevSnp(SevSnpConfig { + is_snp: false, + cbitpos: details.cbitpos, + firmware: hypervisor_config.boot_info.firmware.clone(), + certs_path: "".to_owned(), + }))) + } + GuestProtection::Snp(details) => { + if hypervisor_config.boot_info.firmware.is_empty() { + return Err(anyhow!("SEV-SNP protection requires a path to firmaware")); + } + + // If we got here SEV-SNP is available. However, if + // 'sev_snp_guest' is 'false' in the configuration file we + // still have to revert to SEV. + let is_snp = hypervisor_config.security_info.sev_snp_guest; + if !is_snp { + info!(sl!(), "reverting to SEV even though SEV-SNP is available as requested by 'sev_snp_guest'"); + } + + let certs_path = if is_snp { + hypervisor_config.security_info.snp_certs_path.clone() + } else { + "".to_owned() + }; + + Ok(Some(ProtectionDeviceConfig::SevSnp(SevSnpConfig { + is_snp, + cbitpos: details.cbitpos, + firmware: hypervisor_config.boot_info.firmware.clone(), + certs_path, + }))) + } + _ => Err(anyhow!("confidential_guest requested by configuration but no supported protection available")) + } + } + fn has_prestart_hooks( &self, prestart_hooks: &[oci::Hook],