fix(options): stamp initrd and combine options safely by ignoring empty strings

This commit is contained in:
2025-10-27 17:44:30 -04:00
parent a76f9770dc
commit 26315fb4c4
3 changed files with 44 additions and 20 deletions

View File

@@ -53,13 +53,9 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
let mut loaded_image_protocol = uefi::boot::open_protocol_exclusive::<LoadedImage>(image)
.context("unable to open loaded image protocol")?;
// Stamp and concatenate the options to pass to the image.
let options = configuration
.options
.iter()
.map(|item| context.stamp(item))
.collect::<Vec<_>>()
.join(" ");
// Stamp and combine the options to pass to the image.
let options =
utils::combine_options(configuration.options.iter().map(|item| context.stamp(item)));
// Pass the options to the image, if any are provided.
// The holder must drop at the end of this function to ensure the options are not leaked,
@@ -90,16 +86,14 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
}
// The initrd can be None or empty, so we need to collapse that into a single Option.
let initrd = configuration
.linux_initrd
.as_ref()
.map(|path| context.stamp(path))
.and_then(|path| if path.is_empty() { None } else { Some(path) });
let initrd = utils::empty_is_none(configuration.linux_initrd.as_ref());
// If an initrd is provided, register it with the EFI stack.
let mut initrd_handle = None;
if let Some(ref linux_initrd) = initrd {
let content = utils::read_file_contents(context.root().loaded_image_path()?, linux_initrd)
if let Some(linux_initrd) = initrd {
// Stamp the path to the initrd.
let linux_initrd = context.stamp(linux_initrd);
let content = utils::read_file_contents(context.root().loaded_image_path()?, &linux_initrd)
.context("unable to read linux initrd")?;
let handle =
MediaLoaderHandle::register(LINUX_EFI_INITRD_MEDIA_GUID, content.into_boxed_slice())

View File

@@ -40,7 +40,23 @@ pub struct EderaConfiguration {
}
/// Builds a configuration string for the Xen EFI stub using the specified `configuration`.
fn build_xen_config(configuration: &EderaConfiguration) -> String {
fn build_xen_config(context: Rc<SproutContext>, configuration: &EderaConfiguration) -> String {
// Stamp xen options and combine them.
let xen_options = utils::combine_options(
configuration
.xen_options
.iter()
.map(|item| context.stamp(item)),
);
// Stamp kernel options and combine them.
let kernel_options = utils::combine_options(
configuration
.kernel_options
.iter()
.map(|item| context.stamp(item)),
);
// xen config file format is ini-like
[
// global section
@@ -50,10 +66,10 @@ fn build_xen_config(configuration: &EderaConfiguration) -> String {
// configuration section for sprout
"[sprout]".to_string(),
// xen options
format!("options={}", configuration.xen_options.join(" ")),
format!("options={}", xen_options),
// kernel options, stub replaces the kernel path
// the kernel is provided via media loader
format!("kernel=stub {}", configuration.kernel_options.join(" ")),
format!("kernel=stub {}", kernel_options),
// required or else the last line will be ignored
"".to_string(),
]
@@ -94,7 +110,7 @@ fn register_media_loader_file(
/// `configuration` and `context`. This action uses Edera-specific Xen EFI stub functionality.
pub fn edera(context: Rc<SproutContext>, configuration: &EderaConfiguration) -> Result<()> {
// Build the Xen config file content for this configuration.
let config = build_xen_config(configuration);
let config = build_xen_config(context.clone(), configuration);
// Register the media loader for the config.
let config = register_media_loader_text(XEN_EFI_CONFIG_MEDIA_GUID, "config", config)
@@ -113,7 +129,7 @@ pub fn edera(context: Rc<SproutContext>, configuration: &EderaConfiguration) ->
let mut media_loaders = vec![config, kernel];
// Register the initrd if it is provided.
if let Some(ref initrd) = configuration.initrd {
if let Some(initrd) = utils::empty_is_none(configuration.initrd.as_ref()) {
let initrd =
register_media_loader_file(&context, XEN_EFI_RAMDISK_MEDIA_GUID, "initrd", initrd)
.context("unable to register initrd media loader")?;
@@ -131,7 +147,7 @@ pub fn edera(context: Rc<SproutContext>, configuration: &EderaConfiguration) ->
)
.context("unable to chainload to xen");
// Unregister the media loaders on error.
// Unregister the media loaders when an error happens.
for media_loader in media_loaders {
if let Err(error) = media_loader.unregister() {
error!("unable to unregister media loader: {}", error);