From 401c3b8c1ce5eacdaad4e736739d1bfda72b3bdb Mon Sep 17 00:00:00 2001 From: Julian Stecklina Date: Mon, 28 Nov 2022 02:39:36 +0100 Subject: [PATCH] lanzatool, lanzaboote: don't wrap initrd as PE ... because we check its integrity using the embedded blake3 hash. So there is no need for the LoadImage hack anymore. --- rust/lanzaboote/src/linux_loader.rs | 63 +---------------------------- rust/lanzatool/src/cli.rs | 3 -- rust/lanzatool/src/install.rs | 11 +++-- rust/lanzatool/src/pe.rs | 10 ----- 4 files changed, 7 insertions(+), 80 deletions(-) diff --git a/rust/lanzaboote/src/linux_loader.rs b/rust/lanzaboote/src/linux_loader.rs index 3afbea0..71286ac 100644 --- a/rust/lanzaboote/src/linux_loader.rs +++ b/rust/lanzaboote/src/linux_loader.rs @@ -5,7 +5,7 @@ //! because we read the initrd multiple times. The code needs to be //! restructured to solve this. -use core::{ffi::c_void, ops::Range, pin::Pin, ptr::slice_from_raw_parts_mut}; +use core::{ffi::c_void, pin::Pin, ptr::slice_from_raw_parts_mut}; use alloc::{boxed::Box, vec::Vec}; use uefi::{ @@ -14,7 +14,6 @@ use uefi::{ device_path::{DevicePath, FfiDevicePath}, Protocol, }, - table::boot::LoadImageSource, unsafe_guid, Handle, Identify, Result, ResultExt, Status, }; @@ -115,70 +114,12 @@ pub struct InitrdLoader { registered: bool, } -/// Returns the data range of the initrd in the PE binary. -/// -/// The initrd has to be embedded in the file as a .initrd PE section. -fn initrd_location(initrd_efi: &[u8]) -> Result> { - let pe_binary = goblin::pe::PE::parse(initrd_efi).map_err(|_| Status::INVALID_PARAMETER)?; - - pe_binary - .sections - .iter() - .find(|s| s.name().unwrap() == ".initrd") - .map(|s| { - let section_start: usize = s.pointer_to_raw_data.try_into().unwrap(); - let section_size: usize = s.size_of_raw_data.try_into().unwrap(); - - Range { - start: section_start, - end: section_start + section_size, - } - }) - .ok_or_else(|| Status::END_OF_FILE.into()) -} - -/// Check the signature of the initrd. -/// -/// For this to work, the initrd needs to be a PE binary. We misuse -/// [`BootServices::load_image`] for this. -fn initrd_verify(boot_services: &BootServices, initrd_efi: &[u8]) -> Result<()> { - let initrd_handle = boot_services.load_image( - boot_services.image_handle(), - LoadImageSource::FromBuffer { - buffer: &initrd_efi, - file_path: None, - }, - )?; - - // If we get here, the security policy allowed loading the - // image. This means that it was signed with an acceptable key in - // the Secure Boot scenario. - - boot_services.unload_image(initrd_handle)?; - - Ok(()) -} - impl InitrdLoader { /// Create a new [`InitrdLoader`]. /// /// `handle` is the handle where the protocols are registered /// on. `file` is the file that is served to Linux. - pub fn new( - boot_services: &BootServices, - handle: Handle, - mut initrd_data: Vec, - ) -> Result { - initrd_verify(boot_services, &initrd_data)?; - - let range = initrd_location(&initrd_data)?; - - // Remove the PE wrapper from the initrd. We do this in place - // to avoid having to keep the initrd in memory twice. - initrd_data.drain(0..range.start); - initrd_data.resize(range.end - range.start, 0); - initrd_data.shrink_to_fit(); - + pub fn new(boot_services: &BootServices, handle: Handle, initrd_data: Vec) -> Result { let mut proto = Box::pin(LoadFile2Protocol { load_file: raw_load_file, initrd_data, diff --git a/rust/lanzatool/src/cli.rs b/rust/lanzatool/src/cli.rs index 5d8946e..ec51cf4 100644 --- a/rust/lanzatool/src/cli.rs +++ b/rust/lanzatool/src/cli.rs @@ -59,14 +59,11 @@ impl Commands { fn install(args: InstallCommand) -> Result<()> { let lanzaboote_stub = std::env::var("LANZABOOTE_STUB").context("Failed to read LANZABOOTE_STUB env variable")?; - let initrd_stub = std::env::var("LANZABOOTE_INITRD_STUB") - .context("Failed to read LANZABOOTE_INITRD_STUB env variable")?; let key_pair = KeyPair::new(&args.public_key, &args.private_key); install::Installer::new( PathBuf::from(lanzaboote_stub), - PathBuf::from(initrd_stub), key_pair, args.pki_bundle, args.auto_enroll, diff --git a/rust/lanzatool/src/install.rs b/rust/lanzatool/src/install.rs index 0044acb..ffa5c3f 100644 --- a/rust/lanzatool/src/install.rs +++ b/rust/lanzatool/src/install.rs @@ -14,7 +14,6 @@ use crate::signature::KeyPair; pub struct Installer { lanzaboote_stub: PathBuf, - initrd_stub: PathBuf, key_pair: KeyPair, _pki_bundle: Option, _auto_enroll: bool, @@ -25,7 +24,6 @@ pub struct Installer { impl Installer { pub fn new( lanzaboote_stub: PathBuf, - initrd_stub: PathBuf, key_pair: KeyPair, _pki_bundle: Option, _auto_enroll: bool, @@ -34,7 +32,6 @@ impl Installer { ) -> Self { Self { lanzaboote_stub, - initrd_stub, key_pair, _pki_bundle, _auto_enroll, @@ -94,8 +91,6 @@ impl Installer { if let Some(initrd_secrets_script) = &bootspec.initrd_secrets { append_initrd_secrets(initrd_secrets_script, &initrd_location)?; } - let wrapped_initrd = pe::wrap_initrd(&secure_temp_dir, &self.initrd_stub, &initrd_location) - .context("Failed to assemble stub")?; println!("Sign and copy files to EFI system partition..."); @@ -107,11 +102,15 @@ impl Installer { (&systemd_boot, &esp_paths.efi_fallback), (&systemd_boot, &esp_paths.systemd_boot), (&bootspec.kernel, &esp_paths.kernel), - (&wrapped_initrd, &esp_paths.initrd), ] .into_iter() .try_for_each(|(from, to)| install_signed(&self.key_pair, from, to))?; + // The initrd doesn't need to be signed. Lanzaboote has its + // hash embedded and will refuse loading it when the has + // mismatches. + copy(&initrd_location, &esp_paths.initrd).context("Failed to copy initrd to ESP")?; + let lanzaboote_image = pe::lanzaboote_image( &secure_temp_dir, &self.lanzaboote_stub, diff --git a/rust/lanzatool/src/pe.rs b/rust/lanzatool/src/pe.rs index 994d3ea..a91851c 100644 --- a/rust/lanzatool/src/pe.rs +++ b/rust/lanzatool/src/pe.rs @@ -76,16 +76,6 @@ fn file_hash(file: &Path) -> Result { Ok(blake3::hash(&fs::read(file)?)) } -/// Wrap an initrd into a PE binary. -/// -/// This is required for lanzaboote to verify the signature of the -/// initrd. -pub fn wrap_initrd(target_dir: &TempDir, initrd_stub: &Path, initrd: &Path) -> Result { - let initrd_offs = stub_offset(initrd_stub)?; - let sections = vec![s(".initrd", initrd, initrd_offs)]; - wrap_in_pe(target_dir, "wrapped-initrd.exe", initrd_stub, sections) -} - /// Take a PE binary stub and attach sections to it. /// /// The result is then written to a new file. Returns the filename of