From ae10852f650914bd8201e1b95dd718c5b32b9b29 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 3 Dec 2025 14:05:10 -0500 Subject: [PATCH] libvirt: Fix custom secure boot logic - The nvram path needs to be absolute (would be nice if we could pass this as a file descriptor instead, but hard to do AFAIK with libvirt today) - When a custom nvram is specified, we need to avoid using firmware="efi" as it's mutually exclusive with explicit paths - Also need to explicitly specify `raw` format for nvram No tests yet, but I did test this locally as part of updating bootc's composefs+UKI integration test suite. Signed-off-by: Colin Walters --- crates/kit/src/libvirt/domain.rs | 20 +++++++++++++------- crates/kit/src/libvirt/run.rs | 6 +++++- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/crates/kit/src/libvirt/domain.rs b/crates/kit/src/libvirt/domain.rs index 0e3baae..392b1ee 100644 --- a/crates/kit/src/libvirt/domain.rs +++ b/crates/kit/src/libvirt/domain.rs @@ -209,11 +209,12 @@ impl DomainBuilder { && (self.firmware == Some(FirmwareType::UefiSecure) || self.ovmf_code_path.is_some()); let insecure_boot = self.firmware == Some(FirmwareType::UefiInsecure); - if use_uefi { - writer.start_element("os", &[("firmware", "efi")])?; - } else { - writer.start_element("os", &[])?; - } + // Don't use firmware="efi" when we have custom OVMF paths (secure boot with custom keys) + // because firmware="efi" and explicit paths are mutually exclusive + let os_attributes = (use_uefi && self.ovmf_code_path.is_none()) + .then_some([("firmware", "efi")].as_slice()) + .unwrap_or_default(); + writer.start_element("os", os_attributes)?; // For secure boot on x86_64, we may need a specific machine type with SMM let machine_type = if secure_boot && arch_config.arch == "x86_64" { @@ -231,7 +232,8 @@ impl DomainBuilder { if use_uefi { if let Some(ref ovmf_code) = self.ovmf_code_path { // Use custom OVMF_CODE path for secure boot - let mut loader_attrs = vec![("readonly", "yes"), ("type", "pflash")]; + let mut loader_attrs = + vec![("readonly", "yes"), ("type", "pflash"), ("format", "raw")]; if secure_boot { loader_attrs.push(("secure", "yes")); } @@ -242,7 +244,11 @@ impl DomainBuilder { writer.write_text_element_with_attrs( "nvram", "", // Empty content, template attr provides the source - &[("template", nvram_template)], + &[ + ("template", nvram_template), + ("templateFormat", "raw"), + ("format", "raw"), + ], )?; } } else if secure_boot { diff --git a/crates/kit/src/libvirt/run.rs b/crates/kit/src/libvirt/run.rs index 16d16fa..8ec723e 100644 --- a/crates/kit/src/libvirt/run.rs +++ b/crates/kit/src/libvirt/run.rs @@ -1129,9 +1129,13 @@ fn create_libvirt_domain_from_disk( if let Some(ref sb_config) = secure_boot_config { let ovmf_code = crate::libvirt::secureboot::find_ovmf_code_secboot() .context("Failed to find OVMF_CODE.secboot.fd")?; + let sb_vars_path = sb_config + .vars_template + .canonicalize_utf8() + .context("Canonicalizing secureboot vars path")?; domain_builder = domain_builder .with_ovmf_code_path(ovmf_code.as_str()) - .with_nvram_template(sb_config.vars_template.as_str()); + .with_nvram_template(sb_vars_path.as_str()); // Add secure boot keys path to metadata for reference domain_builder =