rework secure boot override
This commit is contained in:
@ -1,14 +1,13 @@
|
||||
use core::{ffi::c_void, mem::MaybeUninit};
|
||||
|
||||
use uefi::{
|
||||
guid,
|
||||
prelude::BootServices,
|
||||
proto::device_path::{build, DevicePath},
|
||||
Identify, Status,
|
||||
Guid, Identify, Status,
|
||||
};
|
||||
|
||||
const LOADFILE2_GUID: uefi::Guid = guid!("4006c0c1-fcb3-403e-996d-4a6c8724e06d");
|
||||
const LINUX_INITRD_DEVICE_GUID: uefi::Guid = guid!("5568e427-68fc-4f3d-ac74-ca555231cc68");
|
||||
const LOADFILE2_GUID: Guid = Guid::parse_or_panic("4006c0c1-fcb3-403e-996d-4a6c8724e06d");
|
||||
const LINUX_INITRD_DEVICE_GUID: Guid = Guid::parse_or_panic("5568e427-68fc-4f3d-ac74-ca555231cc68");
|
||||
|
||||
/// Extends the LoadFile2 interface with initrd buffer location and size
|
||||
pub struct Loader {
|
||||
@ -71,7 +70,7 @@ pub fn make_initrd_device_path<'a>(buf: &'a mut [MaybeUninit<u8>; 256]) -> &'a D
|
||||
/// Copies data if valid
|
||||
fn initrd_loadfile2(
|
||||
this: *const Loader,
|
||||
_proto: *const c_void,
|
||||
_file_path: *const c_void,
|
||||
_boot_policy: bool,
|
||||
size: *mut usize,
|
||||
buf: *mut c_void,
|
||||
@ -83,7 +82,7 @@ fn initrd_loadfile2(
|
||||
*size = (*this).size;
|
||||
return Status::BUFFER_TOO_SMALL;
|
||||
}
|
||||
core::ptr::copy_nonoverlapping((*this).buf, buf, (*this).size);
|
||||
(*this).buf.copy_to(buf, (*this).size);
|
||||
}
|
||||
Status::SUCCESS
|
||||
}
|
||||
|
||||
41
src/linux.rs
41
src/linux.rs
@ -8,7 +8,7 @@ use uefi::{
|
||||
use crate::{
|
||||
initrd::{install_initrd, make_loader},
|
||||
pe::BootSections,
|
||||
secureboot::install_security_override,
|
||||
secureboot::run_in_security_override,
|
||||
unicode::convert_8_to_16,
|
||||
};
|
||||
|
||||
@ -20,33 +20,30 @@ pub fn start_linux(
|
||||
boot_services: &BootServices,
|
||||
sections: BootSections,
|
||||
) -> Result {
|
||||
// Override Secure Boot loader
|
||||
let uninstall = install_security_override(boot_services);
|
||||
|
||||
// Load kernel as image from memory
|
||||
// Load kernel as image from memory ignoring secure boot
|
||||
// Image is already trusted (signed) by being part of this EFI program
|
||||
let handle = unsafe {
|
||||
boot_services
|
||||
.load_image(
|
||||
image_handle,
|
||||
LoadImageSource::FromBuffer {
|
||||
buffer: &*slice_from_raw_parts::<u8>(
|
||||
sections.linux.pointer,
|
||||
sections.linux.size as usize,
|
||||
),
|
||||
file_path: None,
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
run_in_security_override(boot_services, || {
|
||||
boot_services
|
||||
.load_image(
|
||||
image_handle,
|
||||
LoadImageSource::FromBuffer {
|
||||
buffer: &*slice_from_raw_parts::<u8>(
|
||||
sections.linux.pointer,
|
||||
sections.linux.size as usize,
|
||||
),
|
||||
file_path: None,
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
};
|
||||
|
||||
// Remove secure boot override
|
||||
uninstall();
|
||||
|
||||
let mut linux_image = boot_services
|
||||
.open_protocol_exclusive::<LoadedImage>(handle)
|
||||
.unwrap();
|
||||
|
||||
// Set cmdline for kernel image
|
||||
// Set cmdline for kernel image (expected as utf16)
|
||||
let (cmdline_utf16, cmdline_utf16_size) = convert_8_to_16(
|
||||
boot_services,
|
||||
sections.cmdline.pointer,
|
||||
@ -62,7 +59,7 @@ pub fn start_linux(
|
||||
);
|
||||
|
||||
// Install virtual initrd device
|
||||
// Buffer is used to build the device path
|
||||
// Buffer is used to build the device path, also needs to exist here for lifespan reasons
|
||||
let mut buf = [MaybeUninit::<u8>::uninit(); 256];
|
||||
install_initrd(boot_services, &mut buf, loader);
|
||||
|
||||
|
||||
@ -1,51 +1,33 @@
|
||||
use core::ffi::c_void;
|
||||
|
||||
use log::info;
|
||||
use uefi::{guid, prelude::BootServices, proto::Protocol, Identify};
|
||||
use uefi::{prelude::BootServices, proto::unsafe_protocol};
|
||||
|
||||
#[unsafe_protocol("A46423E3-4617-49F1-B9FF-D1BFA9115839")]
|
||||
struct SecurityArch {
|
||||
pub handler: *const c_void,
|
||||
}
|
||||
|
||||
unsafe impl Identify for SecurityArch {
|
||||
const GUID: uefi::Guid = guid!("A46423E3-4617-49F1-B9FF-D1BFA9115839");
|
||||
}
|
||||
|
||||
impl Protocol for SecurityArch {}
|
||||
|
||||
#[unsafe_protocol("94ab2f58-1438-4ef1-9152-18941a3a0e68")]
|
||||
struct Security2Arch {
|
||||
pub handler: *const c_void,
|
||||
}
|
||||
|
||||
unsafe impl Identify for Security2Arch {
|
||||
const GUID: uefi::Guid = guid!("94ab2f58-1438-4ef1-9152-18941a3a0e68");
|
||||
}
|
||||
|
||||
impl Protocol for Security2Arch {}
|
||||
|
||||
/// Most basic security handler, always returns true
|
||||
/// The ultimate yes-man
|
||||
fn security_handler() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Stores default security handlers to restore them when uninstalling
|
||||
struct DefaultSecurityHandlers {
|
||||
pub security1: Option<*mut *const c_void>,
|
||||
pub security1_handler: Option<*const c_void>,
|
||||
pub security2: Option<*mut *const c_void>,
|
||||
pub security2_handler: Option<*const c_void>,
|
||||
}
|
||||
|
||||
/// Secure Boot override to load kernel image from memory
|
||||
/// Runs a function with a blind secure boot validator
|
||||
/// Plagiarized from systemd-stub's "hack"
|
||||
/// Returns an override uninstaller to restore default handlers
|
||||
pub fn install_security_override(boot_services: &BootServices) -> impl Fn() -> () {
|
||||
let mut defaults = DefaultSecurityHandlers {
|
||||
security1: None,
|
||||
security1_handler: None,
|
||||
security2: None,
|
||||
security2_handler: None,
|
||||
};
|
||||
/// There must be a better way
|
||||
pub fn run_in_security_override<R, T: Fn() -> R>(boot_services: &BootServices, function: T) -> R {
|
||||
// Backup storage
|
||||
let mut df_security1 = None;
|
||||
let mut df_security1_handler = None;
|
||||
let mut df_security2 = None;
|
||||
let mut df_security2_handler = None;
|
||||
// Obtain SecurityArch protocol and replace handler
|
||||
boot_services
|
||||
.get_handle_for_protocol::<SecurityArch>()
|
||||
@ -53,8 +35,8 @@ pub fn install_security_override(boot_services: &BootServices) -> impl Fn() -> (
|
||||
boot_services
|
||||
.open_protocol_exclusive::<SecurityArch>(h)
|
||||
.and_then(|mut security| {
|
||||
defaults.security1 = Some(core::ptr::addr_of_mut!(security.handler));
|
||||
defaults.security1_handler = Some(security.handler);
|
||||
df_security1 = Some(core::ptr::addr_of_mut!(security.handler));
|
||||
df_security1_handler = Some(security.handler);
|
||||
security.handler = security_handler as *const c_void;
|
||||
Ok(())
|
||||
})
|
||||
@ -73,8 +55,8 @@ pub fn install_security_override(boot_services: &BootServices) -> impl Fn() -> (
|
||||
boot_services
|
||||
.open_protocol_exclusive::<Security2Arch>(h)
|
||||
.and_then(|mut security| {
|
||||
defaults.security2 = Some(core::ptr::addr_of_mut!(security.handler));
|
||||
defaults.security2_handler = Some(security.handler);
|
||||
df_security2 = Some(core::ptr::addr_of_mut!(security.handler));
|
||||
df_security2_handler = Some(security.handler);
|
||||
security.handler = security_handler as *const c_void;
|
||||
Ok(())
|
||||
})
|
||||
@ -87,20 +69,13 @@ pub fn install_security_override(boot_services: &BootServices) -> impl Fn() -> (
|
||||
info!("security2 not found");
|
||||
});
|
||||
|
||||
// Returns restore function
|
||||
return move || {
|
||||
// Restore default SecurityArch handler
|
||||
defaults.security1.and_then(|s1| {
|
||||
defaults
|
||||
.security1_handler
|
||||
.and_then(|s1h| Some(unsafe { *s1 = s1h }))
|
||||
});
|
||||
let x = function();
|
||||
|
||||
// Restore default SecurityArch2 handler
|
||||
defaults.security2.and_then(|s2| {
|
||||
defaults
|
||||
.security1_handler
|
||||
.and_then(|s2h| Some(unsafe { *s2 = s2h }))
|
||||
});
|
||||
};
|
||||
// Restore default SecurityArch handler
|
||||
df_security1.and_then(|s1| df_security1_handler.and_then(|s1h| Some(unsafe { *s1 = s1h })));
|
||||
|
||||
// Restore default SecurityArch2 handler
|
||||
df_security2.and_then(|s2| df_security2_handler.and_then(|s2h| Some(unsafe { *s2 = s2h })));
|
||||
|
||||
x
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user