From 7655b589d679bcad0831bc2a465673553faa7f46 Mon Sep 17 00:00:00 2001 From: Altareos Date: Thu, 16 Nov 2023 19:14:31 +0100 Subject: [PATCH] rework secure boot override --- Cargo.lock | 73 ++++++++++++++++++++++++++++++++--------------- Cargo.toml | 8 +++--- src/initrd.rs | 11 ++++--- src/linux.rs | 41 ++++++++++++-------------- src/secureboot.rs | 73 ++++++++++++++++------------------------------- 5 files changed, 102 insertions(+), 104 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9704c17..2b7ad08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "barnacle" -version = "0.1.0" +version = "0.2.0" dependencies = [ "log", "uefi", @@ -19,9 +19,9 @@ checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" [[package]] name = "bitflags" -version = "1.3.2" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "cfg-if" @@ -31,18 +31,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -64,14 +61,14 @@ checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -87,6 +84,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "ucs2" version = "0.3.2" @@ -98,33 +106,46 @@ dependencies = [ [[package]] name = "uefi" -version = "0.19.1" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5607fef843201070ed442fa257c7a944fae963fac7d4620612123192eb4d844" +checksum = "07ead9f748a4646479b850add36b527113a80e80a7e0f44d7b0334291850dcc5" dependencies = [ "bitflags", "log", "ptr_meta", "ucs2", "uefi-macros", + "uefi-raw", + "uguid", ] [[package]] name = "uefi-macros" -version = "0.10.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8099684193f2d99f7f130951f4054a1591ff7da370e2b33d7a71f0434920499" +checksum = "26a7b1c2c808c3db854a54d5215e3f7e7aaf5dcfbce095598cba6af29895695d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", +] + +[[package]] +name = "uefi-raw" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864ac69eadd877bfb34e7814be1928122ed0057d9f975169a56ee496aa7bdfd7" +dependencies = [ + "bitflags", + "ptr_meta", + "uguid", ] [[package]] name = "uefi-services" -version = "0.16.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75daa44f951cc1d9dc68d98cabc06ddbccc221d7bd21222271be5d7ac526a9d" +checksum = "a79fcb420624743c895bad0f9480fbc2f64e7c8d8611fb1ada6bdd799942feb4" dependencies = [ "cfg-if", "log", @@ -132,7 +153,13 @@ dependencies = [ ] [[package]] -name = "unicode-ident" -version = "1.0.8" +name = "uguid" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "1ef516f0806c5f61da6aa95125d0eb2d91cc95b2df426c06bde8be657282aee5" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/Cargo.toml b/Cargo.toml index cda065f..f3ae585 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "barnacle" -version = "0.1.0" +version = "0.2.0" edition = "2021" [[bin]] @@ -15,6 +15,6 @@ bench = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -log = "0.4.17" -uefi = "0.19.1" -uefi-services = "0.16.0" +log = "0.4.20" +uefi = "0.26.0" +uefi-services = "0.23.0" diff --git a/src/initrd.rs b/src/initrd.rs index ca645be..8921466 100644 --- a/src/initrd.rs +++ b/src/initrd.rs @@ -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; 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 } diff --git a/src/linux.rs b/src/linux.rs index 07c1ea3..c93a7cf 100644 --- a/src/linux.rs +++ b/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::( - 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::( + 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::(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::::uninit(); 256]; install_initrd(boot_services, &mut buf, loader); diff --git a/src/secureboot.rs b/src/secureboot.rs index b3a38a5..cc8e4c6 100644 --- a/src/secureboot.rs +++ b/src/secureboot.rs @@ -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>(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::() @@ -53,8 +35,8 @@ pub fn install_security_override(boot_services: &BootServices) -> impl Fn() -> ( boot_services .open_protocol_exclusive::(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::(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 }