vmm: Introduce kernel hashes measured boot

This introduces the kernel hashes measured boot table into
cloud hypervisor if a cmdline and kernel is passed into an
SEV-SNP CVM, incorporating a kernel/cmdline/optional initrd
into a memory page that is measured into the launch digest
of a SEV-SNP CVM. If both --kernel and --cmdline are not
provided, we do not insert this data page

Signed-off-by: Kevin Hui <kevinhui@meta.com>
This commit is contained in:
Kevin Hui
2026-04-22 12:31:15 -07:00
committed by Rob Bradford
parent 9f1247fe60
commit 70388fb1bb
7 changed files with 487 additions and 8 deletions

View File

@@ -105,6 +105,13 @@ use crate::migration::get_vm_snapshot;
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
use crate::migration::url_to_file;
use crate::migration::{SNAPSHOT_CONFIG_FILE, SNAPSHOT_STATE_FILE, url_to_path};
#[cfg(all(
feature = "kvm",
feature = "sev_snp",
feature = "fw_cfg",
target_arch = "x86_64"
))]
use crate::sev::MeasuredBootInfo;
#[cfg(feature = "fw_cfg")]
use crate::vm_config::FwCfgConfig;
use crate::vm_config::{
@@ -1545,6 +1552,13 @@ impl Vm {
igvm_file: IgvmFile,
memory_manager: Arc<Mutex<MemoryManager>>,
cpu_manager: Arc<Mutex<cpu::CpuManager>>,
#[cfg(all(
feature = "kvm",
feature = "sev_snp",
feature = "fw_cfg",
target_arch = "x86_64"
))]
measured_boot: Option<MeasuredBootInfo>,
#[cfg(feature = "sev_snp")] host_data: &Option<String>,
) -> Result<EntryPoint> {
// Only reserve bootloader/VMSA regions for KVM + SEV-SNP; other hypervisors
@@ -1561,6 +1575,13 @@ impl Vm {
memory_manager,
cpu_manager.clone(),
"",
#[cfg(all(
feature = "kvm",
feature = "sev_snp",
feature = "fw_cfg",
target_arch = "x86_64"
))]
measured_boot,
#[cfg(feature = "sev_snp")]
host_data,
)
@@ -1655,10 +1676,61 @@ impl Vm {
if payload.igvm.is_some() {
let igvm_file =
igvm_file.ok_or(Error::IgvmLoad(igvm_loader::Error::MissingIgvm))?;
#[cfg(all(
feature = "kvm",
feature = "sev_snp",
feature = "fw_cfg",
target_arch = "x86_64"
))]
let measured_boot = if let (true, Some(kernel_path), Some(_cmdline)) = (
payload
.fw_cfg_config
.as_ref()
.is_some_and(|cfg| cfg.kernel && cfg.cmdline),
payload.kernel.as_ref(),
payload.cmdline.as_ref(),
) {
let kernel = File::open(kernel_path).map_err(Error::KernelFile)?;
let initramfs = if payload
.fw_cfg_config
.as_ref()
.is_some_and(|cfg| cfg.initramfs)
{
payload
.initramfs
.as_ref()
.map(File::open)
.transpose()
.map_err(Error::InitramfsFile)?
} else {
None
};
// Must byte-match the cmdline that populate_fw_cfg sends to the guest,
// otherwise the launch measurement will diverge.
let cmdline = Self::generate_cmdline(payload)?
.as_cstring()
.map_err(Error::CmdLineCreate)?;
Some(MeasuredBootInfo {
kernel,
initramfs,
cmdline,
})
} else {
None
};
return Self::load_igvm(
igvm_file,
memory_manager,
cpu_manager,
#[cfg(all(
feature = "kvm",
feature = "sev_snp",
feature = "fw_cfg",
target_arch = "x86_64"
))]
measured_boot,
#[cfg(feature = "sev_snp")]
&payload.host_data,
);