rework secure boot override

This commit is contained in:
2023-11-16 19:14:31 +01:00
parent 29b63e1848
commit 7655b589d6
5 changed files with 102 additions and 104 deletions

73
Cargo.lock generated
View File

@ -4,7 +4,7 @@ version = 3
[[package]] [[package]]
name = "barnacle" name = "barnacle"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"log", "log",
"uefi", "uefi",
@ -19,9 +19,9 @@ checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -31,18 +31,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.17" version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.51" version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -64,14 +61,14 @@ checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 1.0.109",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.23" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -87,6 +84,17 @@ dependencies = [
"unicode-ident", "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]] [[package]]
name = "ucs2" name = "ucs2"
version = "0.3.2" version = "0.3.2"
@ -98,33 +106,46 @@ dependencies = [
[[package]] [[package]]
name = "uefi" name = "uefi"
version = "0.19.1" version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5607fef843201070ed442fa257c7a944fae963fac7d4620612123192eb4d844" checksum = "07ead9f748a4646479b850add36b527113a80e80a7e0f44d7b0334291850dcc5"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"log", "log",
"ptr_meta", "ptr_meta",
"ucs2", "ucs2",
"uefi-macros", "uefi-macros",
"uefi-raw",
"uguid",
] ]
[[package]] [[package]]
name = "uefi-macros" name = "uefi-macros"
version = "0.10.0" version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8099684193f2d99f7f130951f4054a1591ff7da370e2b33d7a71f0434920499" checksum = "26a7b1c2c808c3db854a54d5215e3f7e7aaf5dcfbce095598cba6af29895695d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "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]] [[package]]
name = "uefi-services" name = "uefi-services"
version = "0.16.0" version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f75daa44f951cc1d9dc68d98cabc06ddbccc221d7bd21222271be5d7ac526a9d" checksum = "a79fcb420624743c895bad0f9480fbc2f64e7c8d8611fb1ada6bdd799942feb4"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"log", "log",
@ -132,7 +153,13 @@ dependencies = [
] ]
[[package]] [[package]]
name = "unicode-ident" name = "uguid"
version = "1.0.8" version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" 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"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "barnacle" name = "barnacle"
version = "0.1.0" version = "0.2.0"
edition = "2021" edition = "2021"
[[bin]] [[bin]]
@ -15,6 +15,6 @@ bench = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
log = "0.4.17" log = "0.4.20"
uefi = "0.19.1" uefi = "0.26.0"
uefi-services = "0.16.0" uefi-services = "0.23.0"

View File

@ -1,14 +1,13 @@
use core::{ffi::c_void, mem::MaybeUninit}; use core::{ffi::c_void, mem::MaybeUninit};
use uefi::{ use uefi::{
guid,
prelude::BootServices, prelude::BootServices,
proto::device_path::{build, DevicePath}, proto::device_path::{build, DevicePath},
Identify, Status, Guid, Identify, Status,
}; };
const LOADFILE2_GUID: uefi::Guid = guid!("4006c0c1-fcb3-403e-996d-4a6c8724e06d"); const LOADFILE2_GUID: Guid = Guid::parse_or_panic("4006c0c1-fcb3-403e-996d-4a6c8724e06d");
const LINUX_INITRD_DEVICE_GUID: uefi::Guid = guid!("5568e427-68fc-4f3d-ac74-ca555231cc68"); 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 /// Extends the LoadFile2 interface with initrd buffer location and size
pub struct Loader { 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 /// Copies data if valid
fn initrd_loadfile2( fn initrd_loadfile2(
this: *const Loader, this: *const Loader,
_proto: *const c_void, _file_path: *const c_void,
_boot_policy: bool, _boot_policy: bool,
size: *mut usize, size: *mut usize,
buf: *mut c_void, buf: *mut c_void,
@ -83,7 +82,7 @@ fn initrd_loadfile2(
*size = (*this).size; *size = (*this).size;
return Status::BUFFER_TOO_SMALL; return Status::BUFFER_TOO_SMALL;
} }
core::ptr::copy_nonoverlapping((*this).buf, buf, (*this).size); (*this).buf.copy_to(buf, (*this).size);
} }
Status::SUCCESS Status::SUCCESS
} }

View File

@ -8,7 +8,7 @@ use uefi::{
use crate::{ use crate::{
initrd::{install_initrd, make_loader}, initrd::{install_initrd, make_loader},
pe::BootSections, pe::BootSections,
secureboot::install_security_override, secureboot::run_in_security_override,
unicode::convert_8_to_16, unicode::convert_8_to_16,
}; };
@ -20,33 +20,30 @@ pub fn start_linux(
boot_services: &BootServices, boot_services: &BootServices,
sections: BootSections, sections: BootSections,
) -> Result { ) -> Result {
// Override Secure Boot loader // Load kernel as image from memory ignoring secure boot
let uninstall = install_security_override(boot_services); // Image is already trusted (signed) by being part of this EFI program
// Load kernel as image from memory
let handle = unsafe { let handle = unsafe {
boot_services run_in_security_override(boot_services, || {
.load_image( boot_services
image_handle, .load_image(
LoadImageSource::FromBuffer { image_handle,
buffer: &*slice_from_raw_parts::<u8>( LoadImageSource::FromBuffer {
sections.linux.pointer, buffer: &*slice_from_raw_parts::<u8>(
sections.linux.size as usize, sections.linux.pointer,
), sections.linux.size as usize,
file_path: None, ),
}, file_path: None,
) },
.unwrap() )
.unwrap()
})
}; };
// Remove secure boot override
uninstall();
let mut linux_image = boot_services let mut linux_image = boot_services
.open_protocol_exclusive::<LoadedImage>(handle) .open_protocol_exclusive::<LoadedImage>(handle)
.unwrap(); .unwrap();
// Set cmdline for kernel image // Set cmdline for kernel image (expected as utf16)
let (cmdline_utf16, cmdline_utf16_size) = convert_8_to_16( let (cmdline_utf16, cmdline_utf16_size) = convert_8_to_16(
boot_services, boot_services,
sections.cmdline.pointer, sections.cmdline.pointer,
@ -62,7 +59,7 @@ pub fn start_linux(
); );
// Install virtual initrd device // 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]; let mut buf = [MaybeUninit::<u8>::uninit(); 256];
install_initrd(boot_services, &mut buf, loader); install_initrd(boot_services, &mut buf, loader);

View File

@ -1,51 +1,33 @@
use core::ffi::c_void; use core::ffi::c_void;
use log::info; 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 { struct SecurityArch {
pub handler: *const c_void, pub handler: *const c_void,
} }
unsafe impl Identify for SecurityArch { #[unsafe_protocol("94ab2f58-1438-4ef1-9152-18941a3a0e68")]
const GUID: uefi::Guid = guid!("A46423E3-4617-49F1-B9FF-D1BFA9115839");
}
impl Protocol for SecurityArch {}
struct Security2Arch { struct Security2Arch {
pub handler: *const c_void, 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 /// Most basic security handler, always returns true
/// The ultimate yes-man
fn security_handler() -> bool { fn security_handler() -> bool {
true true
} }
/// Stores default security handlers to restore them when uninstalling /// Runs a function with a blind secure boot validator
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
/// Plagiarized from systemd-stub's "hack" /// Plagiarized from systemd-stub's "hack"
/// Returns an override uninstaller to restore default handlers /// There must be a better way
pub fn install_security_override(boot_services: &BootServices) -> impl Fn() -> () { pub fn run_in_security_override<R, T: Fn() -> R>(boot_services: &BootServices, function: T) -> R {
let mut defaults = DefaultSecurityHandlers { // Backup storage
security1: None, let mut df_security1 = None;
security1_handler: None, let mut df_security1_handler = None;
security2: None, let mut df_security2 = None;
security2_handler: None, let mut df_security2_handler = None;
};
// Obtain SecurityArch protocol and replace handler // Obtain SecurityArch protocol and replace handler
boot_services boot_services
.get_handle_for_protocol::<SecurityArch>() .get_handle_for_protocol::<SecurityArch>()
@ -53,8 +35,8 @@ pub fn install_security_override(boot_services: &BootServices) -> impl Fn() -> (
boot_services boot_services
.open_protocol_exclusive::<SecurityArch>(h) .open_protocol_exclusive::<SecurityArch>(h)
.and_then(|mut security| { .and_then(|mut security| {
defaults.security1 = Some(core::ptr::addr_of_mut!(security.handler)); df_security1 = Some(core::ptr::addr_of_mut!(security.handler));
defaults.security1_handler = Some(security.handler); df_security1_handler = Some(security.handler);
security.handler = security_handler as *const c_void; security.handler = security_handler as *const c_void;
Ok(()) Ok(())
}) })
@ -73,8 +55,8 @@ pub fn install_security_override(boot_services: &BootServices) -> impl Fn() -> (
boot_services boot_services
.open_protocol_exclusive::<Security2Arch>(h) .open_protocol_exclusive::<Security2Arch>(h)
.and_then(|mut security| { .and_then(|mut security| {
defaults.security2 = Some(core::ptr::addr_of_mut!(security.handler)); df_security2 = Some(core::ptr::addr_of_mut!(security.handler));
defaults.security2_handler = Some(security.handler); df_security2_handler = Some(security.handler);
security.handler = security_handler as *const c_void; security.handler = security_handler as *const c_void;
Ok(()) Ok(())
}) })
@ -87,20 +69,13 @@ pub fn install_security_override(boot_services: &BootServices) -> impl Fn() -> (
info!("security2 not found"); info!("security2 not found");
}); });
// Returns restore function let x = function();
return move || {
// Restore default SecurityArch handler
defaults.security1.and_then(|s1| {
defaults
.security1_handler
.and_then(|s1h| Some(unsafe { *s1 = s1h }))
});
// Restore default SecurityArch2 handler // Restore default SecurityArch handler
defaults.security2.and_then(|s2| { df_security1.and_then(|s1| df_security1_handler.and_then(|s1h| Some(unsafe { *s1 = s1h })));
defaults
.security1_handler // Restore default SecurityArch2 handler
.and_then(|s2h| Some(unsafe { *s2 = s2h })) df_security2.and_then(|s2| df_security2_handler.and_then(|s2h| Some(unsafe { *s2 = s2h })));
});
}; x
} }