Skip to content

Commit 93042c8

Browse files
Johan-Liebert1cgwalters
authored andcommitted
composefs/boot: Change the way we find sharable vmlinuz + initrd
Instead of looking in the ".origin" files and trying to match the boot_digest to digests in other origin files, we now simply re-compute the sha256sum for vmlinuz + initrd for all boot entries present. This fixes the bug that arises after mutiple upgrades where the original deployment that created the boot entry has been garbage collected, so we end up linking to another deployment that does have the same boot digest, but the verity digest doesn't match the verity digest used for the name of the directory where we store the kernel + initrd pair. Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
1 parent c9b50cb commit 93042c8

1 file changed

Lines changed: 54 additions & 76 deletions

File tree

  • crates/lib/src/bootc_composefs

crates/lib/src/bootc_composefs/boot.rs

Lines changed: 54 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,7 @@ use crate::{
116116
};
117117
use crate::{
118118
composefs_consts::{
119-
BOOT_LOADER_ENTRIES, ORIGIN_KEY_BOOT, ORIGIN_KEY_BOOT_DIGEST, STAGED_BOOT_LOADER_ENTRIES,
120-
STATE_DIR_ABS, USER_CFG, USER_CFG_STAGED,
119+
BOOT_LOADER_ENTRIES, STAGED_BOOT_LOADER_ENTRIES, USER_CFG, USER_CFG_STAGED,
121120
},
122121
spec::{Bootloader, Host},
123122
};
@@ -328,6 +327,27 @@ fn compute_boot_digest(
328327
Ok(hex::encode(digest))
329328
}
330329

330+
#[context("Computing boot digest for Type1 entries")]
331+
fn compute_boot_digest_type1(dir: &Dir) -> Result<String> {
332+
let mut vmlinuz = dir
333+
.open(VMLINUZ)
334+
.with_context(|| format!("Opening {VMLINUZ}"))?;
335+
336+
let mut initrd = dir
337+
.open(INITRD)
338+
.with_context(|| format!("Opening {INITRD}"))?;
339+
340+
let mut hasher = openssl::hash::Hasher::new(openssl::hash::MessageDigest::sha256())
341+
.context("Creating hasher")?;
342+
343+
std::io::copy(&mut vmlinuz, &mut hasher)?;
344+
std::io::copy(&mut initrd, &mut hasher)?;
345+
346+
let digest: &[u8] = &hasher.finish().context("Finishing digest")?;
347+
348+
Ok(hex::encode(digest))
349+
}
350+
331351
/// Compute SHA256Sum of .linux + .initrd section of the UKI
332352
///
333353
/// # Arguments
@@ -355,52 +375,35 @@ pub(crate) fn compute_boot_digest_uki(uki: &[u8]) -> Result<String> {
355375
/// Given the SHA256 sum of current VMlinuz + Initrd combo, find boot entry with the same SHA256Sum
356376
///
357377
/// # Returns
358-
/// Returns the verity of all deployments that have a boot digest same as the one passed in
378+
/// Returns the directory name that has the same sha256 digest for vmlinuz + initrd as the one
379+
/// that's passed in
359380
#[context("Checking boot entry duplicates")]
360-
pub(crate) fn find_vmlinuz_initrd_duplicates(digest: &str) -> Result<Option<Vec<String>>> {
361-
let deployments = Dir::open_ambient_dir(STATE_DIR_ABS, ambient_authority());
362-
363-
let deployments = match deployments {
364-
Ok(d) => d,
365-
// The first ever deployment
366-
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(None),
367-
Err(e) => anyhow::bail!(e),
368-
};
369-
370-
let mut symlink_to: Option<Vec<String>> = None;
371-
372-
for depl in deployments.entries()? {
373-
let depl = depl?;
374-
375-
let depl_file_name = depl.file_name();
376-
let depl_file_name = depl_file_name.as_str()?;
377-
378-
let config = depl
379-
.open_dir()
380-
.with_context(|| format!("Opening {depl_file_name}"))?
381-
.read_to_string(format!("{depl_file_name}.origin"))
382-
.context("Reading origin file")?;
381+
pub(crate) fn find_vmlinuz_initrd_duplicate(
382+
storage: &Storage,
383+
digest: &str,
384+
) -> Result<Option<String>> {
385+
let boot_dir = storage.bls_boot_binaries_dir()?;
386+
387+
for entry in boot_dir.entries_utf8()? {
388+
let entry = entry?;
389+
let dir_name = entry.file_name()?;
390+
391+
if !entry.file_type()?.is_dir() {
392+
continue;
393+
}
383394

384-
let ini = tini::Ini::from_string(&config)
385-
.with_context(|| format!("Failed to parse file {depl_file_name}.origin as ini"))?;
395+
let Some(..) = dir_name.strip_prefix(TYPE1_BOOT_DIR_PREFIX) else {
396+
continue;
397+
};
386398

387-
match ini.get::<String>(ORIGIN_KEY_BOOT, ORIGIN_KEY_BOOT_DIGEST) {
388-
Some(hash) => {
389-
if hash == digest {
390-
match symlink_to {
391-
Some(ref mut prev) => prev.push(depl_file_name.to_string()),
392-
None => symlink_to = Some(vec![depl_file_name.to_string()]),
393-
}
394-
}
395-
}
399+
let entry_digest = compute_boot_digest_type1(&boot_dir.open_dir(&dir_name)?)?;
396400

397-
// No SHASum recorded in origin file
398-
// `symlink_to` is already none, but being explicit here
399-
None => symlink_to = None,
400-
};
401+
if entry_digest == digest {
402+
return Ok(Some(dir_name));
403+
}
401404
}
402405

403-
Ok(symlink_to)
406+
Ok(None)
404407
}
405408

406409
#[context("Writing BLS entries to disk")]
@@ -687,45 +690,20 @@ pub(crate) fn setup_composefs_bls_boot(
687690
options: Some(cmdline_refs),
688691
});
689692

690-
match find_vmlinuz_initrd_duplicates(&boot_digest)? {
691-
Some(shared_entries) => {
693+
let shared_entry = match setup_type {
694+
BootSetupType::Setup(_) => None,
695+
BootSetupType::Upgrade((storage, ..)) => {
696+
find_vmlinuz_initrd_duplicate(storage, &boot_digest)?
697+
}
698+
};
699+
700+
match shared_entry {
701+
Some(shared_entry) => {
692702
// Multiple deployments could be using the same kernel + initrd, but there
693703
// would be only one available
694704
//
695705
// Symlinking directories themselves would be better, but vfat does not support
696706
// symlinks
697-
698-
let mut shared_entry: Option<String> = None;
699-
700-
let entries =
701-
Dir::open_ambient_dir(entry_paths.entries_path, ambient_authority())
702-
.context("Opening entries path")?
703-
.entries_utf8()
704-
.context("Getting dir entries")?;
705-
706-
for ent in entries {
707-
let ent = ent?;
708-
// We shouldn't error here as all our file names are UTF-8 compatible
709-
let ent_name = ent.file_name()?;
710-
711-
let Some(entry_verity_part) = ent_name.strip_prefix(TYPE1_BOOT_DIR_PREFIX)
712-
else {
713-
// Not our directory
714-
continue;
715-
};
716-
717-
if shared_entries
718-
.iter()
719-
.any(|shared_ent| shared_ent == entry_verity_part)
720-
{
721-
shared_entry = Some(ent_name);
722-
break;
723-
}
724-
}
725-
726-
let shared_entry = shared_entry
727-
.ok_or_else(|| anyhow::anyhow!("Shared boot binaries not found"))?;
728-
729707
match bls_config.cfg_type {
730708
BLSConfigType::NonEFI {
731709
ref mut linux,

0 commit comments

Comments
 (0)