fix unregistering of media loader

This commit is contained in:
2025-10-18 23:49:00 -07:00
parent 15c7a7f2b5
commit 21123022c6
4 changed files with 51 additions and 18 deletions

View File

@@ -1,7 +1,7 @@
use crate::context::SproutContext; use crate::context::SproutContext;
use crate::utils; use crate::utils;
use crate::utils::media_loader::MediaLoaderHandle; use crate::utils::media_loader::MediaLoaderHandle;
use crate::utils::media_loader::constants::LINUX_EFI_INITRD_MEDIA_GUID; use crate::utils::media_loader::constants::linux::LINUX_EFI_INITRD_MEDIA_GUID;
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use log::{error, info}; use log::{error, info};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -74,10 +74,10 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
let initrd_path = context.stamp(linux_initrd); let initrd_path = context.stamp(linux_initrd);
let content = utils::read_file_contents(context.root().loaded_image_path()?, &initrd_path) let content = utils::read_file_contents(context.root().loaded_image_path()?, &initrd_path)
.context("unable to read linux initrd")?; .context("unable to read linux initrd")?;
initrd_handle = Some( let handle =
MediaLoaderHandle::register(LINUX_EFI_INITRD_MEDIA_GUID, content.into_boxed_slice()) MediaLoaderHandle::register(LINUX_EFI_INITRD_MEDIA_GUID, content.into_boxed_slice())
.context("unable to register linux initrd")?, .context("unable to register linux initrd")?;
); initrd_handle = Some(handle);
} }
let (base, size) = loaded_image_protocol.info(); let (base, size) = loaded_image_protocol.info();

View File

@@ -12,7 +12,7 @@ use crate::{
self, self,
media_loader::{ media_loader::{
MediaLoaderHandle, MediaLoaderHandle,
constants::{ constants::xen::{
XEN_EFI_CONFIG_MEDIA_GUID, XEN_EFI_KERNEL_MEDIA_GUID, XEN_EFI_RAMDISK_MEDIA_GUID, XEN_EFI_CONFIG_MEDIA_GUID, XEN_EFI_KERNEL_MEDIA_GUID, XEN_EFI_RAMDISK_MEDIA_GUID,
}, },
}, },

View File

@@ -13,7 +13,7 @@ pub mod constants;
#[derive(Debug)] #[derive(Debug)]
#[repr(C)] #[repr(C)]
pub struct MediaLoaderProtocol { struct MediaLoaderProtocol {
pub load_file: unsafe extern "efiapi" fn( pub load_file: unsafe extern "efiapi" fn(
this: *mut MediaLoaderProtocol, this: *mut MediaLoaderProtocol,
file_path: *const DevicePathProtocol, file_path: *const DevicePathProtocol,
@@ -25,14 +25,24 @@ pub struct MediaLoaderProtocol {
pub length: usize, pub length: usize,
} }
/// Represents a media loader which has been registered in the UEFI stack.
/// You MUST call [MediaLoaderHandle::unregister] when ready to unregister.
/// [Drop] is not implemented for this type.
pub struct MediaLoaderHandle { pub struct MediaLoaderHandle {
pub guid: Guid, guid: Guid,
pub handle: Handle, handle: Handle,
pub protocol: *mut MediaLoaderProtocol, protocol: *mut MediaLoaderProtocol,
pub path: *mut DevicePath, path: *mut DevicePath,
} }
impl MediaLoaderHandle { impl MediaLoaderHandle {
/// The behavior of this function is derived from how Linux calls it.
///
/// Linux calls this function by first passing a NULL [buffer].
/// We must set the size of the buffer it should allocate in [buffer_size].
/// The next call will pass a buffer of the right size, and we should copy
/// data into that buffer, checking whether it is safe to copy based on
/// the buffer size.
unsafe extern "efiapi" fn load_file( unsafe extern "efiapi" fn load_file(
this: *mut MediaLoaderProtocol, this: *mut MediaLoaderProtocol,
file_path: *const DevicePathProtocol, file_path: *const DevicePathProtocol,
@@ -44,10 +54,14 @@ impl MediaLoaderHandle {
return Status::INVALID_PARAMETER; return Status::INVALID_PARAMETER;
} }
// Boot policy must not be true, as that's special behavior that is irrelevant
// for the media loader concept.
if boot_policy == Boolean::TRUE { if boot_policy == Boolean::TRUE {
return Status::UNSUPPORTED; return Status::UNSUPPORTED;
} }
// SAFETY: Validated as safe because this is checked to be non-null. It is the caller's
// responsibility to ensure that the right pointer is passed for [this].
unsafe { unsafe {
if (*this).length == 0 || (*this).address.is_null() { if (*this).length == 0 || (*this).address.is_null() {
return Status::NOT_FOUND; return Status::NOT_FOUND;
@@ -65,7 +79,7 @@ impl MediaLoaderHandle {
Status::SUCCESS Status::SUCCESS
} }
pub fn device_path(guid: Guid) -> Box<DevicePath> { fn device_path(guid: Guid) -> Box<DevicePath> {
let mut path = Vec::new(); let mut path = Vec::new();
let path = DevicePathBuilder::with_vec(&mut path) let path = DevicePathBuilder::with_vec(&mut path)
.push(&Vendor { .push(&Vendor {
@@ -167,8 +181,15 @@ impl MediaLoaderHandle {
) )
.context("unable to uninstall media loader load file handle")?; .context("unable to uninstall media loader load file handle")?;
let _path = Box::from_raw(self.path); let path = Box::from_raw(self.path);
let _protocol = Box::from_raw(self.protocol); let protocol = Box::from_raw(self.protocol);
let slice =
std::ptr::slice_from_raw_parts_mut(protocol.address as *mut u8, protocol.length);
let data = Box::from_raw(slice);
drop(path);
drop(protocol);
drop(data);
} }
Ok(()) Ok(())

View File

@@ -1,7 +1,19 @@
/// These GUIDs are specific to Linux itself.
pub mod linux {
use uefi::{Guid, guid}; use uefi::{Guid, guid};
/// The device path GUID for the Linux EFI initrd.
pub const LINUX_EFI_INITRD_MEDIA_GUID: Guid = guid!("5568e427-68fc-4f3d-ac74-ca555231cc68"); pub const LINUX_EFI_INITRD_MEDIA_GUID: Guid = guid!("5568e427-68fc-4f3d-ac74-ca555231cc68");
}
/// These GUIDs were created by Edera to support Xen loading data
/// from Sprout and other EFI bootloaders.
pub mod xen {
use uefi::{Guid, guid};
/// The device path GUID for the Xen EFI config.
pub const XEN_EFI_CONFIG_MEDIA_GUID: Guid = guid!("bf61f458-a28e-46cd-93d7-07dac5e8cd66"); pub const XEN_EFI_CONFIG_MEDIA_GUID: Guid = guid!("bf61f458-a28e-46cd-93d7-07dac5e8cd66");
/// The device path GUID for the Xen EFI config.
pub const XEN_EFI_KERNEL_MEDIA_GUID: Guid = guid!("4010c8bf-6ced-40f5-a53f-e820aee8f34b"); pub const XEN_EFI_KERNEL_MEDIA_GUID: Guid = guid!("4010c8bf-6ced-40f5-a53f-e820aee8f34b");
pub const XEN_EFI_RAMDISK_MEDIA_GUID: Guid = guid!("5db1fd01-c3cb-4812-b2ba-8791e52d4a89"); pub const XEN_EFI_RAMDISK_MEDIA_GUID: Guid = guid!("5db1fd01-c3cb-4812-b2ba-8791e52d4a89");
}