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.
This commit is contained in:
parent
1739ffde26
commit
401c3b8c1c
|
@ -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<Range<usize>> {
|
||||
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<u8>,
|
||||
) -> Result<Self> {
|
||||
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<u8>) -> Result<Self> {
|
||||
let mut proto = Box::pin(LoadFile2Protocol {
|
||||
load_file: raw_load_file,
|
||||
initrd_data,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -14,7 +14,6 @@ use crate::signature::KeyPair;
|
|||
|
||||
pub struct Installer {
|
||||
lanzaboote_stub: PathBuf,
|
||||
initrd_stub: PathBuf,
|
||||
key_pair: KeyPair,
|
||||
_pki_bundle: Option<PathBuf>,
|
||||
_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<PathBuf>,
|
||||
_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,
|
||||
|
|
|
@ -76,16 +76,6 @@ fn file_hash(file: &Path) -> Result<blake3::Hash> {
|
|||
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<PathBuf> {
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue