From 88bcd99ca8dc13e67670e601f94a6c9f623b426a Mon Sep 17 00:00:00 2001 From: Raito Bezarius Date: Thu, 9 Nov 2023 19:30:05 +0100 Subject: [PATCH 1/2] stub(*): support dynamic initrds With this feature, it is now possible to load dynamic initrds (possibly read from filesystem or generated on the fly) and extend existing initrds. This feature will be useful to implement addons in the future. --- rust/uefi/stub/src/fat.rs | 6 +++++- rust/uefi/stub/src/main.rs | 8 ++++++-- rust/uefi/stub/src/thin.rs | 7 ++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/rust/uefi/stub/src/fat.rs b/rust/uefi/stub/src/fat.rs index cce30d3..be6cc0a 100644 --- a/rust/uefi/stub/src/fat.rs +++ b/rust/uefi/stub/src/fat.rs @@ -40,7 +40,11 @@ impl EmbeddedConfiguration { } } -pub fn boot_linux(handle: Handle, mut system_table: SystemTable) -> Status { +pub fn boot_linux( + handle: Handle, + mut system_table: SystemTable, + dynamic_initrds: Vec>, +) -> Status { uefi_services::init(&mut system_table).unwrap(); // SAFETY: We get a slice that represents our currently running diff --git a/rust/uefi/stub/src/main.rs b/rust/uefi/stub/src/main.rs index bc5c6de..ff00113 100644 --- a/rust/uefi/stub/src/main.rs +++ b/rust/uefi/stub/src/main.rs @@ -15,6 +15,7 @@ mod thin; #[cfg(all(feature = "fat", feature = "thin"))] compile_error!("A thin and fat stub cannot be produced at the same time, disable either `thin` or `fat` feature"); +use alloc::vec::Vec; use linux_bootloader::efivars::{export_efi_variables, get_loader_features, EfiLoaderFeatures}; use linux_bootloader::measure::measure_image; use linux_bootloader::tpm::tpm_available; @@ -69,15 +70,18 @@ fn main(handle: Handle, mut system_table: SystemTable) -> Status { export_efi_variables(STUB_NAME, &system_table).expect("Failed to export stub EFI variables"); let status; + // A list of dynamically assembled initrds, e.g. credential initrds or system extension + // initrds. + let dynamic_initrds: Vec> = Vec::new(); #[cfg(feature = "fat")] { - status = fat::boot_linux(handle, system_table) + status = fat::boot_linux(handle, system_table, dynamic_initrds) } #[cfg(feature = "thin")] { - status = thin::boot_linux(handle, system_table).status() + status = thin::boot_linux(handle, system_table, dynamic_initrds).status() } status diff --git a/rust/uefi/stub/src/thin.rs b/rust/uefi/stub/src/thin.rs index bf91c5e..5183b82 100644 --- a/rust/uefi/stub/src/thin.rs +++ b/rust/uefi/stub/src/thin.rs @@ -1,3 +1,4 @@ +use alloc::vec::Vec; use log::{error, warn}; use sha2::{Digest, Sha256}; use uefi::{fs::FileSystem, prelude::*, CString16, Result}; @@ -75,7 +76,11 @@ fn check_hash(data: &[u8], expected_hash: Hash, name: &str, secure_boot: bool) - Ok(()) } -pub fn boot_linux(handle: Handle, mut system_table: SystemTable) -> uefi::Result<()> { +pub fn boot_linux( + handle: Handle, + mut system_table: SystemTable, + dynamic_initrds: Vec>, +) -> uefi::Result<()> { uefi_services::init(&mut system_table).unwrap(); // SAFETY: We get a slice that represents our currently running From e2e8059df26a70a43796c60da25d3f4c6b2eb4a5 Mon Sep 17 00:00:00 2001 From: Raito Bezarius Date: Wed, 15 Nov 2023 05:24:59 +0100 Subject: [PATCH 2/2] stub(*): merge dynamically initrds For dynamic usecases, e.g. credentials or system extension images, we have a need for dynamic merging of initrds. --- rust/uefi/stub/src/fat.rs | 15 +++++++++++++-- rust/uefi/stub/src/thin.rs | 10 +++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/rust/uefi/stub/src/fat.rs b/rust/uefi/stub/src/fat.rs index be6cc0a..4840244 100644 --- a/rust/uefi/stub/src/fat.rs +++ b/rust/uefi/stub/src/fat.rs @@ -51,7 +51,7 @@ pub fn boot_linux( // image and then parse the PE data structures from it. This is // safe, because we don't touch any data in the data sections that // might conceivably change while we look at the slice. - let config = unsafe { + let mut config = unsafe { EmbeddedConfiguration::new( booted_image_file(system_table.boot_services()) .unwrap() @@ -67,5 +67,16 @@ pub fn boot_linux( secure_boot_enabled, ); - boot_linux_unchecked(handle, system_table, config.kernel, &cmdline, config.initrd).status() + let mut final_initrd = Vec::new(); + final_initrd.append(&mut config.initrd); + + // Correctness: dynamic initrds are supposed to be validated by caller, + // i.e. they are system extension images or credentials + // that are supposedly measured in TPM2. + // Therefore, it is normal to not verify their hashes against a configuration. + for mut extra_initrd in dynamic_initrds { + final_initrd.append(&mut extra_initrd); + } + + boot_linux_unchecked(handle, system_table, config.kernel, &cmdline, final_initrd).status() } diff --git a/rust/uefi/stub/src/thin.rs b/rust/uefi/stub/src/thin.rs index 5183b82..3817dad 100644 --- a/rust/uefi/stub/src/thin.rs +++ b/rust/uefi/stub/src/thin.rs @@ -99,7 +99,7 @@ pub fn boot_linux( let secure_boot_enabled = get_secure_boot_status(system_table.runtime_services()); let kernel_data; - let initrd_data; + let mut initrd_data; { let file_system = system_table @@ -135,5 +135,13 @@ pub fn boot_linux( secure_boot_enabled, )?; + // Correctness: dynamic initrds are supposed to be validated by caller, + // i.e. they are system extension images or credentials + // that are supposedly measured in TPM2. + // Therefore, it is normal to not verify their hashes against a configuration. + for mut extra_initrd in dynamic_initrds { + initrd_data.append(&mut extra_initrd); + } + boot_linux_unchecked(handle, system_table, kernel_data, &cmdline, initrd_data) }