mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-07-31 07:19:06 +00:00
runtime-rs: ch: Add TDX CH features check
If you attempt to create a container (a TD) on a TDX system using a custom build of Cloud Hypervisor (CH) that was not built with the `tdx` CH feature, Kata will report the following, somewhat cryptic, CH error: ``` ApiError(VmBoot(InvalidPayload)) ``` Newer versions of CH now report their build-time features in the ping API response message so we now use that, if available, to detect this scenario and generate a user-friendly error message instead. This changes improves the readability of `handle_guest_protection()` and adds a couple of additional tests for that method. Fixes: #8152. Signed-off-by: James O. D. Hunt <james.o.hunt@intel.com>
This commit is contained in:
parent
409eadddb2
commit
0e0867f15d
@ -67,6 +67,12 @@ pub struct CloudHypervisorInner {
|
||||
// The cloud-hypervisor device-id is later looked up and used while
|
||||
// removing the device.
|
||||
pub(crate) device_ids: HashMap<String, String>,
|
||||
|
||||
// List of Cloud Hypervisor features enabled at Cloud Hypervisor build-time.
|
||||
//
|
||||
// If the version of CH does not provide these details, the value will be
|
||||
// None.
|
||||
pub(crate) ch_features: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
const CH_DEFAULT_TIMEOUT_SECS: u32 = 10;
|
||||
@ -104,6 +110,7 @@ impl CloudHypervisorInner {
|
||||
shutdown_rx: Some(rx),
|
||||
tasks: None,
|
||||
guest_protection_to_use: GuestProtection::NoProtection,
|
||||
ch_features: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,8 @@ use kata_sys_util::protection::{available_guest_protection, GuestProtection};
|
||||
use kata_types::capabilities::{Capabilities, CapabilityBits};
|
||||
use kata_types::config::default::DEFAULT_CH_ROOTFS_TYPE;
|
||||
use lazy_static::lazy_static;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::create_dir_all;
|
||||
use std::os::unix::net::UnixStream;
|
||||
@ -42,6 +44,20 @@ const CH_NAME: &str = "cloud-hypervisor";
|
||||
/// Number of milliseconds to wait before retrying a CH operation.
|
||||
const CH_POLL_TIME_MS: u64 = 50;
|
||||
|
||||
// The name of the CH JSON key for the build-time features list.
|
||||
const CH_FEATURES_KEY: &str = "features";
|
||||
|
||||
// The name of the CH build-time feature for Intel TDX.
|
||||
const CH_FEATURE_TDX: &str = "tdx";
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct VmmPingResponse {
|
||||
pub build_version: String,
|
||||
pub version: String,
|
||||
pub pid: i64,
|
||||
pub features: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug, PartialEq)]
|
||||
pub enum GuestProtectionError {
|
||||
#[error("guest protection requested but no guest protection available")]
|
||||
@ -75,6 +91,14 @@ impl CloudHypervisorInner {
|
||||
.await
|
||||
.context("hypervisor running check failed")?;
|
||||
|
||||
if guest_protection_is_tdx(self.guest_protection_to_use.clone()) {
|
||||
if let Some(features) = &self.ch_features {
|
||||
if !features.contains(&CH_FEATURE_TDX.to_string()) {
|
||||
return Err(anyhow!("Cloud Hypervisor is not built with TDX support"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.state = VmmState::VmmServerReady;
|
||||
|
||||
Ok(())
|
||||
@ -424,6 +448,33 @@ impl CloudHypervisorInner {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Check the specified ping API response to see if it contains CH's
|
||||
// build-time features list. If so, save them.
|
||||
async fn handle_ch_build_features(&mut self, ping_response: &str) -> Result<()> {
|
||||
let v: Value = serde_json::from_str(ping_response)?;
|
||||
|
||||
let got = &v[CH_FEATURES_KEY];
|
||||
|
||||
if got.is_null() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let features_list = got
|
||||
.as_array()
|
||||
.ok_or("expected CH to return array of features")
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
let features: Vec<String> = features_list
|
||||
.iter()
|
||||
.map(Value::to_string)
|
||||
.map(|s| s.trim_start_matches('"').trim_end_matches('"').to_string())
|
||||
.collect();
|
||||
|
||||
self.ch_features = Some(features);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn cloud_hypervisor_ping_until_ready(&mut self, _poll_time_ms: u64) -> Result<()> {
|
||||
let socket = self
|
||||
.api_socket
|
||||
@ -439,7 +490,11 @@ impl CloudHypervisorInner {
|
||||
|
||||
if let Ok(response) = response {
|
||||
if let Some(detail) = response {
|
||||
// Check for a list of built-in features, returned by this
|
||||
// API call in newer versions of CH.
|
||||
debug!(sl!(), "ping response: {:?}", detail);
|
||||
|
||||
self.handle_ch_build_features(&detail).await?;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user