mirror of
https://github.com/edera-dev/sprout.git
synced 2026-11-04 18:42:21 +00:00
fix(initrd): pad each chained initrd to a 4-byte boundary
Chained initrds were concatenated back to back. Linux only finds a cpio archive at a 4-byte aligned offset when it unpacks concatenated initrds, so a compressed initramfs with an odd length followed by another archive, like a microcode or overlay cpio, failed to unpack. Pad each initrd with zeros to a 4-byte boundary, as GRUB and systemd-boot do.
This commit is contained in:
1 parent
cd38f0271d
commit
e96a5a64c9
3 files changed
+37
-4
No files matched your search
@@ -5,7 +5,7 @@ use alloc::rc::Rc;
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use anyhow::{Context, Result, bail};
|
use anyhow::{Context, Result, bail};
|
||||||
use edera_sprout_config::actions::chainload::ChainloadConfiguration;
|
use edera_sprout_config::actions::chainload::ChainloadConfiguration;
|
||||||
use edera_sprout_parsing::{combine_options, empty_is_none};
|
use edera_sprout_parsing::{append_initrd, combine_options, empty_is_none};
|
||||||
use eficore::bootloader_interface::BootloaderInterface;
|
use eficore::bootloader_interface::BootloaderInterface;
|
||||||
use eficore::loader::source::ImageSource;
|
use eficore::loader::source::ImageSource;
|
||||||
use eficore::loader::{ImageLoadRequest, ImageLoader};
|
use eficore::loader::{ImageLoadRequest, ImageLoader};
|
||||||
@@ -112,7 +112,7 @@ pub fn chainload(context: Rc<SproutContext>, configuration: &ChainloadConfigurat
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
match initrd.as_mut() {
|
match initrd.as_mut() {
|
||||||
Some(initrd) => initrd.extend_from_slice(&content),
|
Some(initrd) => append_initrd(initrd, &content),
|
||||||
None => initrd = Some(content),
|
None => initrd = Some(content),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use alloc::{format, vec};
|
|||||||
use anyhow::{Context, Result, bail};
|
use anyhow::{Context, Result, bail};
|
||||||
use edera_sprout_config::actions::chainload::ChainloadConfiguration;
|
use edera_sprout_config::actions::chainload::ChainloadConfiguration;
|
||||||
use edera_sprout_config::actions::edera::EderaConfiguration;
|
use edera_sprout_config::actions::edera::EderaConfiguration;
|
||||||
use edera_sprout_parsing::{build_xen_config, combine_options, empty_is_none};
|
use edera_sprout_parsing::{append_initrd, build_xen_config, combine_options, empty_is_none};
|
||||||
use eficore::media_loader::{
|
use eficore::media_loader::{
|
||||||
MediaLoaderHandle,
|
MediaLoaderHandle,
|
||||||
constants::xen::{
|
constants::xen::{
|
||||||
@@ -94,7 +94,10 @@ pub fn edera(context: Rc<SproutContext>, configuration: &EderaConfiguration) ->
|
|||||||
.chain(configuration.initrd_chain.iter())
|
.chain(configuration.initrd_chain.iter())
|
||||||
{
|
{
|
||||||
if let Some(p) = empty_is_none(Some(p)) {
|
if let Some(p) = empty_is_none(Some(p)) {
|
||||||
initrd_bytes.extend(read_loader_payload(&context, "initrd", p)?);
|
append_initrd(
|
||||||
|
&mut initrd_bytes,
|
||||||
|
&read_loader_payload(&context, "initrd", p)?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PlatformTpm::log_event(
|
PlatformTpm::log_event(
|
||||||
|
|||||||
@@ -90,6 +90,18 @@ pub fn combine_options<T: AsRef<str>>(options: impl Iterator<Item = T>) -> Strin
|
|||||||
.join(" ")
|
.join(" ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The alignment of each initrd when initrds are concatenated.
|
||||||
|
const INITRD_ALIGNMENT: usize = 4;
|
||||||
|
|
||||||
|
/// Append the `initrd` to the concatenated `initrds`, padding with zeros so that it starts
|
||||||
|
/// on a 4-byte boundary. Linux only finds a cpio archive at a 4-byte aligned offset when
|
||||||
|
/// unpacking concatenated initrds, as GRUB and systemd-boot pad them the same way.
|
||||||
|
pub fn append_initrd(initrds: &mut Vec<u8>, initrd: &[u8]) {
|
||||||
|
let padded = initrds.len().next_multiple_of(INITRD_ALIGNMENT);
|
||||||
|
initrds.resize(padded, 0);
|
||||||
|
initrds.extend_from_slice(initrd);
|
||||||
|
}
|
||||||
|
|
||||||
/// Produce a unique hash for the input.
|
/// Produce a unique hash for the input.
|
||||||
/// This uses SHA-256, which is unique enough but relatively short.
|
/// This uses SHA-256, which is unique enough but relatively short.
|
||||||
pub fn unique_hash(input: &str) -> String {
|
pub fn unique_hash(input: &str) -> String {
|
||||||
@@ -358,6 +370,24 @@ mod tests {
|
|||||||
assert!(config.ends_with('\n'));
|
assert!(config.ends_with('\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn append_initrd_pads_to_four_bytes() {
|
||||||
|
let mut initrds = Vec::new();
|
||||||
|
append_initrd(&mut initrds, b"abcde");
|
||||||
|
assert_eq!(initrds, b"abcde");
|
||||||
|
append_initrd(&mut initrds, b"fg");
|
||||||
|
assert_eq!(initrds, b"abcde\0\0\0fg");
|
||||||
|
append_initrd(&mut initrds, b"h");
|
||||||
|
assert_eq!(initrds, b"abcde\0\0\0fg\0\0h");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn append_initrd_aligned_needs_no_padding() {
|
||||||
|
let mut initrds = b"abcd".to_vec();
|
||||||
|
append_initrd(&mut initrds, b"efgh");
|
||||||
|
assert_eq!(initrds, b"abcdefgh");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn kernel_prefix_exact_match() {
|
fn kernel_prefix_exact_match() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
Reference in new issue
Block a user