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]]
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"

View File

@ -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"

View File

@ -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
}

View File

@ -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);

View File

@ -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
}