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::utils;
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 log::{error, info};
use serde::{Deserialize, Serialize};
@@ -74,10 +74,10 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
let initrd_path = context.stamp(linux_initrd);
let content = utils::read_file_contents(context.root().loaded_image_path()?, &initrd_path)
.context("unable to read linux initrd")?;
initrd_handle = Some(
let handle =
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();

View File

@@ -12,7 +12,7 @@ use crate::{
self,
media_loader::{
MediaLoaderHandle,
constants::{
constants::xen::{
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)]
#[repr(C)]
pub struct MediaLoaderProtocol {
struct MediaLoaderProtocol {
pub load_file: unsafe extern "efiapi" fn(
this: *mut MediaLoaderProtocol,
file_path: *const DevicePathProtocol,
@@ -25,14 +25,24 @@ pub struct MediaLoaderProtocol {
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 guid: Guid,
pub handle: Handle,
pub protocol: *mut MediaLoaderProtocol,
pub path: *mut DevicePath,
guid: Guid,
handle: Handle,
protocol: *mut MediaLoaderProtocol,
path: *mut DevicePath,
}
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(
this: *mut MediaLoaderProtocol,
file_path: *const DevicePathProtocol,
@@ -44,10 +54,14 @@ impl MediaLoaderHandle {
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 {
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 {
if (*this).length == 0 || (*this).address.is_null() {
return Status::NOT_FOUND;
@@ -65,7 +79,7 @@ impl MediaLoaderHandle {
Status::SUCCESS
}
pub fn device_path(guid: Guid) -> Box<DevicePath> {
fn device_path(guid: Guid) -> Box<DevicePath> {
let mut path = Vec::new();
let path = DevicePathBuilder::with_vec(&mut path)
.push(&Vendor {
@@ -167,8 +181,15 @@ impl MediaLoaderHandle {
)
.context("unable to uninstall media loader load file handle")?;
let _path = Box::from_raw(self.path);
let _protocol = Box::from_raw(self.protocol);
let path = Box::from_raw(self.path);
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(())

View File

@@ -1,7 +1,19 @@
use uefi::{Guid, guid};
/// These GUIDs are specific to Linux itself.
pub mod linux {
use uefi::{Guid, guid};
pub const LINUX_EFI_INITRD_MEDIA_GUID: Guid = guid!("5568e427-68fc-4f3d-ac74-ca555231cc68");
/// 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 XEN_EFI_CONFIG_MEDIA_GUID: Guid = guid!("bf61f458-a28e-46cd-93d7-07dac5e8cd66");
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");
/// 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");
/// 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_RAMDISK_MEDIA_GUID: Guid = guid!("5db1fd01-c3cb-4812-b2ba-8791e52d4a89");
}