mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-08 03:24:15 +00:00
runtime-rs: ch: Enable Intel TDX
Allow Cloud Hypervisor to create a confidential guest (a TD or "Trust Domain") rather than a VM (Virtual Machine) on Intel systems that provide TDX functionality. > **Notes:** > > - At least currently, when built with the `tdx` feature, Cloud Hypervisor > cannot create a standard VM on a TDX capable system: it can only create > a TD. This implies that on TDX capable systems, the Kata Configuration > option `confidential_guest=` must be set to `true`. If it is not, Kata > will detect this and display the following error: > > ``` > TDX guest protection available and must be used with Cloud Hypervisor (set 'confidential_guest=true') > ``` > > - This change expands the scope of the protection code, changing > Intel TDX specific booleans to more generic "available guest protection" > code that could be "none" or "TDX", or some other form of guest > protection. Fixes: #6448. Signed-off-by: James O. D. Hunt <james.o.hunt@intel.com>
This commit is contained in:
parent
523399c329
commit
b0a3293d53
71
src/libs/Cargo.lock
generated
71
src/libs/Cargo.lock
generated
@ -172,6 +172,40 @@ dependencies = [
|
|||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.14.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive-new"
|
name = "derive-new"
|
||||||
version = "0.5.9"
|
version = "0.5.9"
|
||||||
@ -448,6 +482,12 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
@ -543,6 +583,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"safe-path",
|
"safe-path",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde-enum-str",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"slog",
|
"slog",
|
||||||
"slog-scope",
|
"slog-scope",
|
||||||
@ -1072,6 +1113,36 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde-attributes"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6eb8ec7724e4e524b2492b510e66957fe1a2c76c26a6975ec80823f2439da685"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"serde-rename-rule",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde-enum-str"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26416dc95fcd46b0e4b12a3758043a229a6914050aaec2e8191949753ed4e9aa"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"serde-attributes",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde-rename-rule"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "794e44574226fc701e3be5c651feb7939038fc67fb73f6f4dd5c4ba90fd3be70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.136"
|
version = "1.0.136"
|
||||||
|
@ -17,8 +17,9 @@ use nix::unistd::Uid;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
pub enum GuestProtection {
|
pub enum GuestProtection {
|
||||||
|
#[default]
|
||||||
NoProtection,
|
NoProtection,
|
||||||
Tdx,
|
Tdx,
|
||||||
Sev,
|
Sev,
|
||||||
|
@ -44,8 +44,12 @@ pub use self::qemu::{QemuConfig, HYPERVISOR_NAME_QEMU};
|
|||||||
mod ch;
|
mod ch;
|
||||||
pub use self::ch::{CloudHypervisorConfig, HYPERVISOR_NAME_CH};
|
pub use self::ch::{CloudHypervisorConfig, HYPERVISOR_NAME_CH};
|
||||||
|
|
||||||
const VIRTIO_BLK_PCI: &str = "virtio-blk-pci";
|
/// Virtual PCI block device driver.
|
||||||
const VIRTIO_BLK_MMIO: &str = "virtio-blk-mmio";
|
pub const VIRTIO_BLK_PCI: &str = "virtio-blk-pci";
|
||||||
|
|
||||||
|
/// Virtual MMIO block device driver.
|
||||||
|
pub const VIRTIO_BLK_MMIO: &str = "virtio-blk-mmio";
|
||||||
|
|
||||||
const VIRTIO_BLK_CCW: &str = "virtio-blk-ccw";
|
const VIRTIO_BLK_CCW: &str = "virtio-blk-ccw";
|
||||||
const VIRTIO_SCSI: &str = "virtio-scsi";
|
const VIRTIO_SCSI: &str = "virtio-scsi";
|
||||||
const VIRTIO_PMEM: &str = "virtio-pmem";
|
const VIRTIO_PMEM: &str = "virtio-pmem";
|
||||||
|
33
src/runtime-rs/Cargo.lock
generated
33
src/runtime-rs/Cargo.lock
generated
@ -454,6 +454,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"api_client",
|
"api_client",
|
||||||
|
"kata-sys-util",
|
||||||
"kata-types",
|
"kata-types",
|
||||||
"nix 0.26.2",
|
"nix 0.26.2",
|
||||||
"serde",
|
"serde",
|
||||||
@ -1402,6 +1403,7 @@ dependencies = [
|
|||||||
"dragonball",
|
"dragonball",
|
||||||
"futures 0.3.28",
|
"futures 0.3.28",
|
||||||
"go-flag",
|
"go-flag",
|
||||||
|
"hypervisor",
|
||||||
"kata-sys-util",
|
"kata-sys-util",
|
||||||
"kata-types",
|
"kata-types",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@ -1416,9 +1418,11 @@ dependencies = [
|
|||||||
"seccompiler",
|
"seccompiler",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"serial_test 2.0.0",
|
||||||
"shim-interface",
|
"shim-interface",
|
||||||
"slog",
|
"slog",
|
||||||
"slog-scope",
|
"slog-scope",
|
||||||
|
"test-utils",
|
||||||
"tests_utils",
|
"tests_utils",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
@ -3049,7 +3053,21 @@ checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"parking_lot 0.11.2",
|
"parking_lot 0.11.2",
|
||||||
"serial_test_derive",
|
"serial_test_derive 0.5.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial_test"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d"
|
||||||
|
dependencies = [
|
||||||
|
"dashmap",
|
||||||
|
"futures 0.3.28",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"parking_lot 0.12.1",
|
||||||
|
"serial_test_derive 2.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3063,6 +3081,17 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial_test_derive"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.27",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "service"
|
name = "service"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -3144,7 +3173,7 @@ dependencies = [
|
|||||||
"protobuf 3.2.0",
|
"protobuf 3.2.0",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"runtimes",
|
"runtimes",
|
||||||
"serial_test",
|
"serial_test 0.5.1",
|
||||||
"service",
|
"service",
|
||||||
"sha2 0.9.3",
|
"sha2 0.9.3",
|
||||||
"slog",
|
"slog",
|
||||||
|
@ -23,7 +23,7 @@ serde_json = ">=1.0.9"
|
|||||||
slog = "2.5.2"
|
slog = "2.5.2"
|
||||||
slog-scope = "4.4.0"
|
slog-scope = "4.4.0"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
tokio = { version = "1.28.1", features = ["sync", "fs"] }
|
tokio = { version = "1.28.1", features = ["sync", "fs", "process", "io-util"] }
|
||||||
vmm-sys-util = "0.11.0"
|
vmm-sys-util = "0.11.0"
|
||||||
rand = "0.8.4"
|
rand = "0.8.4"
|
||||||
path-clean = "1.0.1"
|
path-clean = "1.0.1"
|
||||||
@ -50,3 +50,12 @@ default = []
|
|||||||
# Feature is not yet complete, so not enabled by default.
|
# Feature is not yet complete, so not enabled by default.
|
||||||
# See https://github.com/kata-containers/kata-containers/issues/6264.
|
# See https://github.com/kata-containers/kata-containers/issues/6264.
|
||||||
cloud-hypervisor = ["ch-config"]
|
cloud-hypervisor = ["ch-config"]
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
# Force the CH tests to run, even when the feature is not enabled for
|
||||||
|
# a normal build.
|
||||||
|
hypervisor = { path = ".", features = ["cloud-hypervisor"] }
|
||||||
|
|
||||||
|
test-utils = { path = "../../../libs/test-utils" }
|
||||||
|
|
||||||
|
serial_test = "2.0.0"
|
||||||
|
@ -22,5 +22,6 @@ tokio = { version = "1.28.1", features = ["sync", "rt"] }
|
|||||||
api_client = { git = "https://github.com/cloud-hypervisor/cloud-hypervisor", crate = "api_client", tag = "v27.0" }
|
api_client = { git = "https://github.com/cloud-hypervisor/cloud-hypervisor", crate = "api_client", tag = "v27.0" }
|
||||||
|
|
||||||
kata-types = { path = "../../../../libs/kata-types"}
|
kata-types = { path = "../../../../libs/kata-types"}
|
||||||
|
kata-sys-util = { path = "../../../../libs/kata-sys-util"}
|
||||||
nix = "0.26.2"
|
nix = "0.26.2"
|
||||||
thiserror = "1.0.38"
|
thiserror = "1.0.38"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -41,6 +41,16 @@ pub enum VmConfigError {
|
|||||||
|
|
||||||
#[error("VSOCK config error: {0}")]
|
#[error("VSOCK config error: {0}")]
|
||||||
VsockError(VsockConfigError),
|
VsockError(VsockConfigError),
|
||||||
|
|
||||||
|
#[error("TDX requires virtio-blk VM rootfs driver")]
|
||||||
|
TDXVMRootfsNotVirtioBlk,
|
||||||
|
|
||||||
|
#[error("TDX requires virtio-blk container rootfs block device driver")]
|
||||||
|
TDXContainerRootfsNotVirtioBlk,
|
||||||
|
|
||||||
|
// LIMITATION: Current CH TDX limitation.
|
||||||
|
#[error("TDX requires an image=, not an initrd=")]
|
||||||
|
TDXDisallowsInitrd,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug, PartialEq)]
|
#[derive(Error, Debug, PartialEq)]
|
||||||
@ -60,11 +70,20 @@ pub enum DiskConfigError {
|
|||||||
|
|
||||||
#[derive(Error, Debug, PartialEq)]
|
#[derive(Error, Debug, PartialEq)]
|
||||||
pub enum CpusConfigError {
|
pub enum CpusConfigError {
|
||||||
|
#[error("Boot vCPUs cannot be zero or negative")]
|
||||||
|
BootVCPUsTooSmall,
|
||||||
|
|
||||||
#[error("Too many boot vCPUs specified: {0}")]
|
#[error("Too many boot vCPUs specified: {0}")]
|
||||||
BootVCPUsTooBig(<u8 as TryFrom<i32>>::Error),
|
BootVCPUsTooBig(<u8 as TryFrom<i32>>::Error),
|
||||||
|
|
||||||
|
#[error("Max vCPUs cannot be zero or negative")]
|
||||||
|
MaxVCPUsTooSmall,
|
||||||
|
|
||||||
#[error("Too many max vCPUs specified: {0}")]
|
#[error("Too many max vCPUs specified: {0}")]
|
||||||
MaxVCPUsTooBig(<u8 as TryFrom<u32>>::Error),
|
MaxVCPUsTooBig(<u8 as TryFrom<u32>>::Error),
|
||||||
|
|
||||||
|
#[error("Boot vCPUs cannot be larger than max vCPUs")]
|
||||||
|
BootVPUsGtThanMaxVCPUs,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug, PartialEq)]
|
#[derive(Error, Debug, PartialEq)]
|
||||||
|
@ -12,6 +12,7 @@ pub mod net_util;
|
|||||||
mod virtio_devices;
|
mod virtio_devices;
|
||||||
|
|
||||||
use crate::virtio_devices::RateLimiterConfig;
|
use crate::virtio_devices::RateLimiterConfig;
|
||||||
|
use kata_sys_util::protection::GuestProtection;
|
||||||
use kata_types::config::hypervisor::Hypervisor as HypervisorConfig;
|
use kata_types::config::hypervisor::Hypervisor as HypervisorConfig;
|
||||||
pub use net_util::MacAddr;
|
pub use net_util::MacAddr;
|
||||||
|
|
||||||
@ -489,8 +490,78 @@ pub struct NamedHypervisorConfig {
|
|||||||
pub sandbox_path: String,
|
pub sandbox_path: String,
|
||||||
pub vsock_socket_path: String,
|
pub vsock_socket_path: String,
|
||||||
pub cfg: HypervisorConfig,
|
pub cfg: HypervisorConfig,
|
||||||
pub tdx_enabled: bool,
|
|
||||||
|
|
||||||
pub shared_fs_devices: Option<Vec<FsConfig>>,
|
pub shared_fs_devices: Option<Vec<FsConfig>>,
|
||||||
pub network_devices: Option<Vec<NetConfig>>,
|
pub network_devices: Option<Vec<NetConfig>>,
|
||||||
|
|
||||||
|
// Set to the available guest protection *iff* BOTH of the following
|
||||||
|
// conditions are true:
|
||||||
|
//
|
||||||
|
// - The hardware supports guest protection.
|
||||||
|
// - The user has requested that guest protection be used.
|
||||||
|
pub guest_protection_to_use: GuestProtection,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the enabled guest protection is Intel TDX.
|
||||||
|
pub fn guest_protection_is_tdx(guest_protection_to_use: GuestProtection) -> bool {
|
||||||
|
matches!(guest_protection_to_use, GuestProtection::Tdx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_guest_protection_is_tdx() {
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct TestData {
|
||||||
|
protection: GuestProtection,
|
||||||
|
result: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
let tests = &[
|
||||||
|
TestData {
|
||||||
|
protection: GuestProtection::NoProtection,
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
protection: GuestProtection::Pef,
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
protection: GuestProtection::Se,
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
protection: GuestProtection::Sev,
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
protection: GuestProtection::Snp,
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
protection: GuestProtection::Tdx,
|
||||||
|
result: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (i, d) in tests.iter().enumerate() {
|
||||||
|
let msg = format!("test[{}]: {:?}", i, d);
|
||||||
|
|
||||||
|
let result = guest_protection_is_tdx(d.protection.clone());
|
||||||
|
|
||||||
|
let msg = format!("{}: actual result: {:?}", msg, result);
|
||||||
|
|
||||||
|
if std::env::var("DEBUG").is_ok() {
|
||||||
|
eprintln!("DEBUG: {}", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.result {
|
||||||
|
assert!(result, "{}", msg);
|
||||||
|
} else {
|
||||||
|
assert!(!result, "{}", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ use crate::device::DeviceType;
|
|||||||
use crate::VmmState;
|
use crate::VmmState;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use kata_sys_util::protection::GuestProtection;
|
||||||
use kata_types::capabilities::{Capabilities, CapabilityBits};
|
use kata_types::capabilities::{Capabilities, CapabilityBits};
|
||||||
use kata_types::config::hypervisor::Hypervisor as HypervisorConfig;
|
use kata_types::config::hypervisor::Hypervisor as HypervisorConfig;
|
||||||
use kata_types::config::hypervisor::HYPERVISOR_NAME_CH;
|
use kata_types::config::hypervisor::HYPERVISOR_NAME_CH;
|
||||||
@ -51,6 +52,13 @@ pub struct CloudHypervisorInner {
|
|||||||
pub(crate) shutdown_tx: Option<Sender<bool>>,
|
pub(crate) shutdown_tx: Option<Sender<bool>>,
|
||||||
pub(crate) shutdown_rx: Option<Receiver<bool>>,
|
pub(crate) shutdown_rx: Option<Receiver<bool>>,
|
||||||
pub(crate) tasks: Option<Vec<JoinHandle<Result<()>>>>,
|
pub(crate) tasks: Option<Vec<JoinHandle<Result<()>>>>,
|
||||||
|
|
||||||
|
// Set if the hardware supports creating a protected guest *AND* if the
|
||||||
|
// user has requested creating a protected guest.
|
||||||
|
//
|
||||||
|
// For example, on Intel TDX capable systems with `confidential_guest=true`,
|
||||||
|
// this will be set to "tdx".
|
||||||
|
pub(crate) guest_protection_to_use: GuestProtection,
|
||||||
}
|
}
|
||||||
|
|
||||||
const CH_DEFAULT_TIMEOUT_SECS: u32 = 10;
|
const CH_DEFAULT_TIMEOUT_SECS: u32 = 10;
|
||||||
@ -86,6 +94,7 @@ impl CloudHypervisorInner {
|
|||||||
shutdown_tx: Some(tx),
|
shutdown_tx: Some(tx),
|
||||||
shutdown_rx: Some(rx),
|
shutdown_rx: Some(rx),
|
||||||
tasks: None,
|
tasks: None,
|
||||||
|
guest_protection_to_use: GuestProtection::NoProtection,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,24 +8,27 @@ use crate::ch::utils::get_api_socket_path;
|
|||||||
use crate::ch::utils::get_vsock_path;
|
use crate::ch::utils::get_vsock_path;
|
||||||
use crate::kernel_param::KernelParams;
|
use crate::kernel_param::KernelParams;
|
||||||
use crate::utils::{get_jailer_root, get_sandbox_path};
|
use crate::utils::{get_jailer_root, get_sandbox_path};
|
||||||
use crate::VM_ROOTFS_DRIVER_PMEM;
|
|
||||||
use crate::{VcpuThreadIds, VmmState};
|
use crate::{VcpuThreadIds, VmmState};
|
||||||
|
use crate::{VM_ROOTFS_DRIVER_BLK, VM_ROOTFS_DRIVER_PMEM};
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use ch_config::ch_api::{
|
use ch_config::ch_api::{
|
||||||
cloud_hypervisor_vm_create, cloud_hypervisor_vm_start, cloud_hypervisor_vmm_ping,
|
cloud_hypervisor_vm_create, cloud_hypervisor_vm_start, cloud_hypervisor_vmm_ping,
|
||||||
cloud_hypervisor_vmm_shutdown,
|
cloud_hypervisor_vmm_shutdown,
|
||||||
};
|
};
|
||||||
use ch_config::{NamedHypervisorConfig, VmConfig};
|
use ch_config::{guest_protection_is_tdx, NamedHypervisorConfig, VmConfig};
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use futures::executor::block_on;
|
use futures::executor::block_on;
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
|
use kata_sys_util::protection::{available_guest_protection, GuestProtection};
|
||||||
use kata_types::capabilities::{Capabilities, CapabilityBits};
|
use kata_types::capabilities::{Capabilities, CapabilityBits};
|
||||||
use kata_types::config::default::DEFAULT_CH_ROOTFS_TYPE;
|
use kata_types::config::default::DEFAULT_CH_ROOTFS_TYPE;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fs::create_dir_all;
|
use std::fs::create_dir_all;
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
use tokio::io::AsyncBufReadExt;
|
use tokio::io::AsyncBufReadExt;
|
||||||
use tokio::io::BufReader;
|
use tokio::io::BufReader;
|
||||||
use tokio::process::{Child, Command};
|
use tokio::process::{Child, Command};
|
||||||
@ -39,6 +42,21 @@ const CH_NAME: &str = "cloud-hypervisor";
|
|||||||
/// Number of milliseconds to wait before retrying a CH operation.
|
/// Number of milliseconds to wait before retrying a CH operation.
|
||||||
const CH_POLL_TIME_MS: u64 = 50;
|
const CH_POLL_TIME_MS: u64 = 50;
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug, PartialEq)]
|
||||||
|
pub enum GuestProtectionError {
|
||||||
|
#[error("guest protection requested but no guest protection available")]
|
||||||
|
NoProtectionAvailable,
|
||||||
|
|
||||||
|
// LIMITATION: Current CH TDX limitation.
|
||||||
|
//
|
||||||
|
// When built to support TDX, if Cloud Hypervisor determines the host
|
||||||
|
// system supports TDX, it can only create TD's (as opposed to VMs).
|
||||||
|
// Hence, on a TDX capable system, confidential_guest *MUST* be set to
|
||||||
|
// "true".
|
||||||
|
#[error("TDX guest protection available and must be used with Cloud Hypervisor (set 'confidential_guest=true')")]
|
||||||
|
TDXProtectionMustBeUsedWithCH,
|
||||||
|
}
|
||||||
|
|
||||||
impl CloudHypervisorInner {
|
impl CloudHypervisorInner {
|
||||||
async fn start_hypervisor(&mut self, timeout_secs: i32) -> Result<()> {
|
async fn start_hypervisor(&mut self, timeout_secs: i32) -> Result<()> {
|
||||||
self.cloud_hypervisor_launch(timeout_secs)
|
self.cloud_hypervisor_launch(timeout_secs)
|
||||||
@ -70,7 +88,12 @@ impl CloudHypervisorInner {
|
|||||||
let confidential_guest = cfg.security_info.confidential_guest;
|
let confidential_guest = cfg.security_info.confidential_guest;
|
||||||
|
|
||||||
// Note that the configuration option hypervisor.block_device_driver is not used.
|
// Note that the configuration option hypervisor.block_device_driver is not used.
|
||||||
let rootfs_driver = VM_ROOTFS_DRIVER_PMEM;
|
let rootfs_driver = if confidential_guest {
|
||||||
|
// PMEM is not available with TDX.
|
||||||
|
VM_ROOTFS_DRIVER_BLK
|
||||||
|
} else {
|
||||||
|
VM_ROOTFS_DRIVER_PMEM
|
||||||
|
};
|
||||||
|
|
||||||
let rootfs_type = match cfg.boot_info.rootfs_type.is_empty() {
|
let rootfs_type = match cfg.boot_info.rootfs_type.is_empty() {
|
||||||
true => DEFAULT_CH_ROOTFS_TYPE,
|
true => DEFAULT_CH_ROOTFS_TYPE,
|
||||||
@ -82,7 +105,7 @@ impl CloudHypervisorInner {
|
|||||||
|
|
||||||
let mut rootfs_param = KernelParams::new_rootfs_kernel_params(rootfs_driver, rootfs_type)?;
|
let mut rootfs_param = KernelParams::new_rootfs_kernel_params(rootfs_driver, rootfs_type)?;
|
||||||
|
|
||||||
let mut extra_params = if enable_debug {
|
let mut console_params = if enable_debug {
|
||||||
if confidential_guest {
|
if confidential_guest {
|
||||||
KernelParams::from_string("console=hvc0")
|
KernelParams::from_string("console=hvc0")
|
||||||
} else {
|
} else {
|
||||||
@ -92,11 +115,21 @@ impl CloudHypervisorInner {
|
|||||||
KernelParams::from_string("quiet")
|
KernelParams::from_string("quiet")
|
||||||
};
|
};
|
||||||
|
|
||||||
params.append(&mut extra_params);
|
params.append(&mut console_params);
|
||||||
|
|
||||||
// Add the rootfs device
|
// Add the rootfs device
|
||||||
params.append(&mut rootfs_param);
|
params.append(&mut rootfs_param);
|
||||||
|
|
||||||
|
// Now add some additional options required for CH
|
||||||
|
let extra_options = [
|
||||||
|
"no_timer_check", // Do not Check broken timer IRQ resources
|
||||||
|
"noreplace-smp", // Do not replace SMP instructions
|
||||||
|
"systemd.log_target=console", // Send logging output to the console
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut extra_params = KernelParams::from_string(&extra_options.join(" "));
|
||||||
|
params.append(&mut extra_params);
|
||||||
|
|
||||||
// Finally, add the user-specified options at the end
|
// Finally, add the user-specified options at the end
|
||||||
// (so they will take priority).
|
// (so they will take priority).
|
||||||
params.append(&mut KernelParams::from_string(&cfg.boot_info.kernel_params));
|
params.append(&mut KernelParams::from_string(&cfg.boot_info.kernel_params));
|
||||||
@ -134,25 +167,24 @@ impl CloudHypervisorInner {
|
|||||||
|
|
||||||
let kernel_params = self.get_kernel_params().await?;
|
let kernel_params = self.get_kernel_params().await?;
|
||||||
|
|
||||||
// FIXME: See:
|
|
||||||
//
|
|
||||||
// - https://github.com/kata-containers/kata-containers/issues/6383
|
|
||||||
// - https://github.com/kata-containers/kata-containers/pull/6257
|
|
||||||
let tdx_enabled = false;
|
|
||||||
|
|
||||||
let named_cfg = NamedHypervisorConfig {
|
let named_cfg = NamedHypervisorConfig {
|
||||||
kernel_params,
|
kernel_params,
|
||||||
sandbox_path,
|
sandbox_path,
|
||||||
vsock_socket_path,
|
vsock_socket_path,
|
||||||
cfg: hypervisor_config.clone(),
|
cfg: hypervisor_config.clone(),
|
||||||
tdx_enabled,
|
guest_protection_to_use: self.guest_protection_to_use.clone(),
|
||||||
shared_fs_devices,
|
shared_fs_devices,
|
||||||
network_devices,
|
network_devices,
|
||||||
};
|
};
|
||||||
|
|
||||||
let cfg = VmConfig::try_from(named_cfg)?;
|
let cfg = VmConfig::try_from(named_cfg)?;
|
||||||
|
|
||||||
debug!(sl!(), "CH specific VmConfig configuration: {:?}", cfg);
|
let serialised = serde_json::to_string(&cfg)?;
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
sl!(),
|
||||||
|
"CH specific VmConfig configuration (JSON): {:?}", serialised
|
||||||
|
);
|
||||||
|
|
||||||
let response =
|
let response =
|
||||||
cloud_hypervisor_vm_create(socket.try_clone().context("failed to clone socket")?, cfg)
|
cloud_hypervisor_vm_create(socket.try_clone().context("failed to clone socket")?, cfg)
|
||||||
@ -256,7 +288,7 @@ impl CloudHypervisorInner {
|
|||||||
|
|
||||||
let debug = cfg.debug_info.enable_debug;
|
let debug = cfg.debug_info.enable_debug;
|
||||||
|
|
||||||
let disable_seccomp = true;
|
let disable_seccomp = cfg.security_info.disable_seccomp;
|
||||||
|
|
||||||
let api_socket_path = get_api_socket_path(&self.id)?;
|
let api_socket_path = get_api_socket_path(&self.id)?;
|
||||||
|
|
||||||
@ -289,6 +321,9 @@ impl CloudHypervisorInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
|
// Note that with TDX enabled, this results in a lot of additional
|
||||||
|
// CH output, particularly if the user adds "earlyprintk" to the
|
||||||
|
// guest kernel command line (by modifying "kernel_params=").
|
||||||
cmd.arg("-v");
|
cmd.arg("-v");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,6 +331,8 @@ impl CloudHypervisorInner {
|
|||||||
cmd.args(["--seccomp", "false"]);
|
cmd.args(["--seccomp", "false"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!(sl!(), "launching {} as: {:?}", CH_NAME, cmd);
|
||||||
|
|
||||||
let child = cmd.spawn().context(format!("{} spawn failed", CH_NAME))?;
|
let child = cmd.spawn().context(format!("{} spawn failed", CH_NAME))?;
|
||||||
|
|
||||||
// Save process PID
|
// Save process PID
|
||||||
@ -415,11 +452,55 @@ impl CloudHypervisorInner {
|
|||||||
|
|
||||||
self.setup_environment().await?;
|
self.setup_environment().await?;
|
||||||
|
|
||||||
|
self.handle_guest_protection().await?;
|
||||||
|
|
||||||
self.netns = netns;
|
self.netns = netns;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if guest protection is available and also check if the user
|
||||||
|
// actually wants to use it.
|
||||||
|
//
|
||||||
|
// Note: This method must be called as early as possible since after this
|
||||||
|
// call, if confidential_guest is set, a confidential
|
||||||
|
// guest will be created.
|
||||||
|
async fn handle_guest_protection(&mut self) -> Result<()> {
|
||||||
|
let cfg = self
|
||||||
|
.config
|
||||||
|
.as_ref()
|
||||||
|
.ok_or("missing hypervisor config")
|
||||||
|
.map_err(|e| anyhow!(e))?;
|
||||||
|
|
||||||
|
let confidential_guest = cfg.security_info.confidential_guest;
|
||||||
|
|
||||||
|
if confidential_guest {
|
||||||
|
info!(sl!(), "confidential guest requested");
|
||||||
|
}
|
||||||
|
|
||||||
|
let protection =
|
||||||
|
task::spawn_blocking(|| -> Result<GuestProtection> { get_guest_protection() })
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
if protection == GuestProtection::NoProtection {
|
||||||
|
if confidential_guest {
|
||||||
|
return Err(anyhow!(GuestProtectionError::NoProtectionAvailable));
|
||||||
|
} else {
|
||||||
|
debug!(sl!(), "no guest protection available");
|
||||||
|
}
|
||||||
|
} else if confidential_guest {
|
||||||
|
self.guest_protection_to_use = protection.clone();
|
||||||
|
|
||||||
|
info!(sl!(), "guest protection available and requested"; "guest-protection" => protection.to_string());
|
||||||
|
} else if protection == GuestProtection::Tdx {
|
||||||
|
return Err(anyhow!(GuestProtectionError::TDXProtectionMustBeUsedWithCH));
|
||||||
|
} else {
|
||||||
|
info!(sl!(), "guest protection available but not requested"; "guest-protection" => protection.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn setup_environment(&mut self) -> Result<()> {
|
async fn setup_environment(&mut self) -> Result<()> {
|
||||||
// run_dir and vm_path are the same (shared)
|
// run_dir and vm_path are the same (shared)
|
||||||
self.run_dir = get_sandbox_path(&self.id);
|
self.run_dir = get_sandbox_path(&self.id);
|
||||||
@ -524,7 +605,18 @@ impl CloudHypervisorInner {
|
|||||||
|
|
||||||
pub(crate) async fn capabilities(&self) -> Result<Capabilities> {
|
pub(crate) async fn capabilities(&self) -> Result<Capabilities> {
|
||||||
let mut caps = Capabilities::default();
|
let mut caps = Capabilities::default();
|
||||||
caps.set(CapabilityBits::FsSharingSupport);
|
|
||||||
|
let flags = if guest_protection_is_tdx(self.guest_protection_to_use.clone()) {
|
||||||
|
// TDX does not permit the use of virtio-fs.
|
||||||
|
CapabilityBits::BlockDeviceSupport | CapabilityBits::BlockDeviceHotplugSupport
|
||||||
|
} else {
|
||||||
|
CapabilityBits::BlockDeviceSupport
|
||||||
|
| CapabilityBits::BlockDeviceHotplugSupport
|
||||||
|
| CapabilityBits::FsSharingSupport
|
||||||
|
};
|
||||||
|
|
||||||
|
caps.set(flags);
|
||||||
|
|
||||||
Ok(caps)
|
Ok(caps)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,3 +675,331 @@ async fn cloud_hypervisor_log_output(mut child: Child, mut shutdown: Receiver<bo
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
// Store the fake guest protection value used by
|
||||||
|
// get_fake_guest_protection() and set_fake_guest_protection().
|
||||||
|
//
|
||||||
|
// Note that if this variable is set to None, get_fake_guest_protection()
|
||||||
|
// will fall back to checking the actual guest protection by calling
|
||||||
|
// get_guest_protection().
|
||||||
|
static ref FAKE_GUEST_PROTECTION: Arc<RwLock<Option<GuestProtection>>> =
|
||||||
|
Arc::new(RwLock::new(Some(GuestProtection::NoProtection)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the _fake_ GuestProtection value set by set_guest_protection().
|
||||||
|
fn get_fake_guest_protection() -> Result<GuestProtection> {
|
||||||
|
let existing_ref = FAKE_GUEST_PROTECTION.clone();
|
||||||
|
|
||||||
|
let existing = existing_ref.read().unwrap();
|
||||||
|
|
||||||
|
let real_protection = available_guest_protection()?;
|
||||||
|
|
||||||
|
let protection = if let Some(ref protection) = *existing {
|
||||||
|
protection
|
||||||
|
} else {
|
||||||
|
// XXX: If no fake value is set, fall back to the real function.
|
||||||
|
&real_protection
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(protection.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return available hardware protection, or GuestProtection::NoProtection
|
||||||
|
// if none available.
|
||||||
|
//
|
||||||
|
// XXX: Note that this function wraps the low-level function to determine
|
||||||
|
// guest protection. It does this to allow us to force a particular guest
|
||||||
|
// protection type in the unit tests.
|
||||||
|
fn get_guest_protection() -> Result<GuestProtection> {
|
||||||
|
let guest_protection = if cfg!(test) {
|
||||||
|
get_fake_guest_protection()
|
||||||
|
} else {
|
||||||
|
available_guest_protection().map_err(|e| anyhow!(e.to_string()))
|
||||||
|
}?;
|
||||||
|
|
||||||
|
Ok(guest_protection)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
use kata_sys_util::protection::TDX_SYS_FIRMWARE_DIR;
|
||||||
|
|
||||||
|
use kata_types::config::hypervisor::{Hypervisor as HypervisorConfig, SecurityInfo};
|
||||||
|
use serial_test::serial;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use test_utils::{assert_result, skip_if_not_root};
|
||||||
|
|
||||||
|
fn set_fake_guest_protection(protection: Option<GuestProtection>) {
|
||||||
|
let existing_ref = FAKE_GUEST_PROTECTION.clone();
|
||||||
|
|
||||||
|
let mut existing = existing_ref.write().unwrap();
|
||||||
|
|
||||||
|
// Modify the lazy static global config structure
|
||||||
|
*existing = protection;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serial]
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_get_guest_protection() {
|
||||||
|
// available_guest_protection() requires super user privs.
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct TestData {
|
||||||
|
value: Option<GuestProtection>,
|
||||||
|
result: Result<GuestProtection>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let tests = &[
|
||||||
|
TestData {
|
||||||
|
value: Some(GuestProtection::NoProtection),
|
||||||
|
result: Ok(GuestProtection::NoProtection),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
value: Some(GuestProtection::Pef),
|
||||||
|
result: Ok(GuestProtection::Pef),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
value: Some(GuestProtection::Se),
|
||||||
|
result: Ok(GuestProtection::Se),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
value: Some(GuestProtection::Sev),
|
||||||
|
result: Ok(GuestProtection::Sev),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
value: Some(GuestProtection::Snp),
|
||||||
|
result: Ok(GuestProtection::Snp),
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
value: Some(GuestProtection::Tdx),
|
||||||
|
result: Ok(GuestProtection::Tdx),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (i, d) in tests.iter().enumerate() {
|
||||||
|
let msg = format!("test[{}]: {:?}", i, d);
|
||||||
|
|
||||||
|
set_fake_guest_protection(d.value.clone());
|
||||||
|
|
||||||
|
let result =
|
||||||
|
task::spawn_blocking(|| -> Result<GuestProtection> { get_guest_protection() })
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let msg = format!("{}: actual result: {:?}", msg, result);
|
||||||
|
|
||||||
|
if std::env::var("DEBUG").is_ok() {
|
||||||
|
eprintln!("DEBUG: {}", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_result!(d.result, result, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset
|
||||||
|
set_fake_guest_protection(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
#[serial]
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_get_guest_protection_tdx() {
|
||||||
|
// available_guest_protection() requires super user privs.
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
// Use the hosts protection, not a fake one.
|
||||||
|
set_fake_guest_protection(None);
|
||||||
|
|
||||||
|
let tdx_fw_path = PathBuf::from(TDX_SYS_FIRMWARE_DIR);
|
||||||
|
|
||||||
|
// Simple test for Intel TDX
|
||||||
|
let have_tdx = if tdx_fw_path.exists() {
|
||||||
|
if let Ok(metadata) = std::fs::metadata(tdx_fw_path.clone()) {
|
||||||
|
metadata.is_dir()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
let protection =
|
||||||
|
task::spawn_blocking(|| -> Result<GuestProtection> { get_guest_protection() })
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if std::env::var("DEBUG").is_ok() {
|
||||||
|
let msg = format!(
|
||||||
|
"tdx_fw_path: {:?}, have_tdx: {:?}, protection: {:?}",
|
||||||
|
tdx_fw_path, have_tdx, protection
|
||||||
|
);
|
||||||
|
|
||||||
|
eprintln!("DEBUG: {}", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if have_tdx {
|
||||||
|
assert_eq!(protection, GuestProtection::Tdx);
|
||||||
|
} else {
|
||||||
|
assert_eq!(protection, GuestProtection::NoProtection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[serial]
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_handle_guest_protection() {
|
||||||
|
// available_guest_protection() requires super user privs.
|
||||||
|
skip_if_not_root!();
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct TestData {
|
||||||
|
confidential_guest: bool,
|
||||||
|
available_protection: Option<GuestProtection>,
|
||||||
|
|
||||||
|
result: Result<()>,
|
||||||
|
|
||||||
|
// The expected result (internal state)
|
||||||
|
guest_protection_to_use: GuestProtection,
|
||||||
|
}
|
||||||
|
|
||||||
|
let tests = &[
|
||||||
|
TestData {
|
||||||
|
confidential_guest: false,
|
||||||
|
available_protection: Some(GuestProtection::NoProtection),
|
||||||
|
result: Ok(()),
|
||||||
|
guest_protection_to_use: GuestProtection::NoProtection,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
confidential_guest: true,
|
||||||
|
available_protection: Some(GuestProtection::NoProtection),
|
||||||
|
result: Err(anyhow!(GuestProtectionError::NoProtectionAvailable)),
|
||||||
|
guest_protection_to_use: GuestProtection::NoProtection,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
confidential_guest: false,
|
||||||
|
available_protection: Some(GuestProtection::Tdx),
|
||||||
|
result: Err(anyhow!(GuestProtectionError::TDXProtectionMustBeUsedWithCH)),
|
||||||
|
guest_protection_to_use: GuestProtection::NoProtection,
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
confidential_guest: true,
|
||||||
|
available_protection: Some(GuestProtection::Tdx),
|
||||||
|
result: Ok(()),
|
||||||
|
guest_protection_to_use: GuestProtection::Tdx,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (i, d) in tests.iter().enumerate() {
|
||||||
|
let msg = format!("test[{}]: {:?}", i, d);
|
||||||
|
|
||||||
|
set_fake_guest_protection(d.available_protection.clone());
|
||||||
|
|
||||||
|
let mut ch = CloudHypervisorInner::default();
|
||||||
|
|
||||||
|
let cfg = HypervisorConfig {
|
||||||
|
security_info: SecurityInfo {
|
||||||
|
confidential_guest: d.confidential_guest,
|
||||||
|
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
ch.set_hypervisor_config(cfg);
|
||||||
|
|
||||||
|
let result = ch.handle_guest_protection().await;
|
||||||
|
|
||||||
|
let msg = format!("{}: actual result: {:?}", msg, result);
|
||||||
|
|
||||||
|
if std::env::var("DEBUG").is_ok() {
|
||||||
|
eprintln!("DEBUG: {}", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.result.is_ok() && result.is_ok() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_result!(d.result, result, msg);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
ch.guest_protection_to_use, d.guest_protection_to_use,
|
||||||
|
"{}",
|
||||||
|
msg
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset
|
||||||
|
set_fake_guest_protection(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_get_kernel_params() {
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct TestData<'a> {
|
||||||
|
cfg: Option<HypervisorConfig>,
|
||||||
|
confidential_guest: bool,
|
||||||
|
debug: bool,
|
||||||
|
fails: bool,
|
||||||
|
contains: Vec<&'a str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let tests = &[
|
||||||
|
TestData {
|
||||||
|
cfg: None,
|
||||||
|
confidential_guest: false,
|
||||||
|
debug: false,
|
||||||
|
fails: true, // No hypervisor config
|
||||||
|
contains: vec![],
|
||||||
|
},
|
||||||
|
TestData {
|
||||||
|
cfg: Some(HypervisorConfig::default()),
|
||||||
|
confidential_guest: false,
|
||||||
|
debug: false,
|
||||||
|
fails: false,
|
||||||
|
contains: vec![],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (i, d) in tests.iter().enumerate() {
|
||||||
|
let msg = format!("test[{}]: {:?}", i, d);
|
||||||
|
|
||||||
|
let mut ch = CloudHypervisorInner::default();
|
||||||
|
|
||||||
|
if let Some(ref mut cfg) = d.cfg.clone() {
|
||||||
|
if d.debug {
|
||||||
|
cfg.debug_info.enable_debug = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.confidential_guest {
|
||||||
|
cfg.security_info.confidential_guest = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch.set_hypervisor_config(cfg.clone());
|
||||||
|
|
||||||
|
let result = ch.get_kernel_params().await;
|
||||||
|
|
||||||
|
let msg = format!("{}: actual result: {:?}", msg, result);
|
||||||
|
|
||||||
|
if std::env::var("DEBUG").is_ok() {
|
||||||
|
eprintln!("DEBUG: {}", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.fails {
|
||||||
|
assert!(result.is_err(), "{}", msg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = result.unwrap();
|
||||||
|
|
||||||
|
for token in d.contains.clone() {
|
||||||
|
assert!(result.contains(token), "{}", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user