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
|
//! because we read the initrd multiple times. The code needs to be
|
||||||
//! restructured to solve this.
|
//! 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 alloc::{boxed::Box, vec::Vec};
|
||||||
use uefi::{
|
use uefi::{
|
||||||
|
@ -14,7 +14,6 @@ use uefi::{
|
||||||
device_path::{DevicePath, FfiDevicePath},
|
device_path::{DevicePath, FfiDevicePath},
|
||||||
Protocol,
|
Protocol,
|
||||||
},
|
},
|
||||||
table::boot::LoadImageSource,
|
|
||||||
unsafe_guid, Handle, Identify, Result, ResultExt, Status,
|
unsafe_guid, Handle, Identify, Result, ResultExt, Status,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -115,70 +114,12 @@ pub struct InitrdLoader {
|
||||||
registered: bool,
|
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 {
|
impl InitrdLoader {
|
||||||
/// Create a new [`InitrdLoader`].
|
/// Create a new [`InitrdLoader`].
|
||||||
///
|
///
|
||||||
/// `handle` is the handle where the protocols are registered
|
/// `handle` is the handle where the protocols are registered
|
||||||
/// on. `file` is the file that is served to Linux.
|
/// on. `file` is the file that is served to Linux.
|
||||||
pub fn new(
|
pub fn new(boot_services: &BootServices, handle: Handle, initrd_data: Vec<u8>) -> Result<Self> {
|
||||||
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();
|
|
||||||
|
|
||||||
let mut proto = Box::pin(LoadFile2Protocol {
|
let mut proto = Box::pin(LoadFile2Protocol {
|
||||||
load_file: raw_load_file,
|
load_file: raw_load_file,
|
||||||
initrd_data,
|
initrd_data,
|
||||||
|
|
|
@ -59,14 +59,11 @@ impl Commands {
|
||||||
fn install(args: InstallCommand) -> Result<()> {
|
fn install(args: InstallCommand) -> Result<()> {
|
||||||
let lanzaboote_stub =
|
let lanzaboote_stub =
|
||||||
std::env::var("LANZABOOTE_STUB").context("Failed to read LANZABOOTE_STUB env variable")?;
|
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);
|
let key_pair = KeyPair::new(&args.public_key, &args.private_key);
|
||||||
|
|
||||||
install::Installer::new(
|
install::Installer::new(
|
||||||
PathBuf::from(lanzaboote_stub),
|
PathBuf::from(lanzaboote_stub),
|
||||||
PathBuf::from(initrd_stub),
|
|
||||||
key_pair,
|
key_pair,
|
||||||
args.pki_bundle,
|
args.pki_bundle,
|
||||||
args.auto_enroll,
|
args.auto_enroll,
|
||||||
|
|
|
@ -14,7 +14,6 @@ use crate::signature::KeyPair;
|
||||||
|
|
||||||
pub struct Installer {
|
pub struct Installer {
|
||||||
lanzaboote_stub: PathBuf,
|
lanzaboote_stub: PathBuf,
|
||||||
initrd_stub: PathBuf,
|
|
||||||
key_pair: KeyPair,
|
key_pair: KeyPair,
|
||||||
_pki_bundle: Option<PathBuf>,
|
_pki_bundle: Option<PathBuf>,
|
||||||
_auto_enroll: bool,
|
_auto_enroll: bool,
|
||||||
|
@ -25,7 +24,6 @@ pub struct Installer {
|
||||||
impl Installer {
|
impl Installer {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
lanzaboote_stub: PathBuf,
|
lanzaboote_stub: PathBuf,
|
||||||
initrd_stub: PathBuf,
|
|
||||||
key_pair: KeyPair,
|
key_pair: KeyPair,
|
||||||
_pki_bundle: Option<PathBuf>,
|
_pki_bundle: Option<PathBuf>,
|
||||||
_auto_enroll: bool,
|
_auto_enroll: bool,
|
||||||
|
@ -34,7 +32,6 @@ impl Installer {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
lanzaboote_stub,
|
lanzaboote_stub,
|
||||||
initrd_stub,
|
|
||||||
key_pair,
|
key_pair,
|
||||||
_pki_bundle,
|
_pki_bundle,
|
||||||
_auto_enroll,
|
_auto_enroll,
|
||||||
|
@ -94,8 +91,6 @@ impl Installer {
|
||||||
if let Some(initrd_secrets_script) = &bootspec.initrd_secrets {
|
if let Some(initrd_secrets_script) = &bootspec.initrd_secrets {
|
||||||
append_initrd_secrets(initrd_secrets_script, &initrd_location)?;
|
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...");
|
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.efi_fallback),
|
||||||
(&systemd_boot, &esp_paths.systemd_boot),
|
(&systemd_boot, &esp_paths.systemd_boot),
|
||||||
(&bootspec.kernel, &esp_paths.kernel),
|
(&bootspec.kernel, &esp_paths.kernel),
|
||||||
(&wrapped_initrd, &esp_paths.initrd),
|
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.try_for_each(|(from, to)| install_signed(&self.key_pair, from, to))?;
|
.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(
|
let lanzaboote_image = pe::lanzaboote_image(
|
||||||
&secure_temp_dir,
|
&secure_temp_dir,
|
||||||
&self.lanzaboote_stub,
|
&self.lanzaboote_stub,
|
||||||
|
|
|
@ -76,16 +76,6 @@ fn file_hash(file: &Path) -> Result<blake3::Hash> {
|
||||||
Ok(blake3::hash(&fs::read(file)?))
|
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.
|
/// Take a PE binary stub and attach sections to it.
|
||||||
///
|
///
|
||||||
/// The result is then written to a new file. Returns the filename of
|
/// The result is then written to a new file. Returns the filename of
|
||||||
|
|
Loading…
Reference in New Issue