From 18051369ea5e8658999be8df162500cfd78dfc0b Mon Sep 17 00:00:00 2001 From: Dudecake Date: Wed, 10 Jun 2026 12:30:58 +0000 Subject: [PATCH 1/3] Filter out BLS entries not managed by bootc --- crates/lib/src/bootc_composefs/status.rs | 21 +++++++++++++------ crates/lib/src/composefs_consts.rs | 3 +++ ...est-composefs-corruped-state-resilience.nu | 10 ++++----- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/crates/lib/src/bootc_composefs/status.rs b/crates/lib/src/bootc_composefs/status.rs index c8e7851c3..6d285634f 100644 --- a/crates/lib/src/bootc_composefs/status.rs +++ b/crates/lib/src/bootc_composefs/status.rs @@ -19,6 +19,7 @@ use crate::{ composefs_consts::{ COMPOSEFS_CMDLINE, ORIGIN_KEY_BOOT_DIGEST, ORIGIN_KEY_IMAGE, ORIGIN_KEY_MANIFEST_DIGEST, TYPE1_ENT_PATH, TYPE1_ENT_PATH_STAGED, USER_CFG, USER_CFG_STAGED, + BLS_ENTRY_PREFIX, }, install::EFI_LOADER_INFO, parsers::{ @@ -304,7 +305,7 @@ fn get_sorted_type1_boot_entries_helper( .to_str() .ok_or(anyhow::anyhow!("Found non UTF-8 characters in filename"))?; - if !file_name.ends_with(".conf") { + if !(file_name.starts_with(BLS_ENTRY_PREFIX) && file_name.ends_with(".conf")) { continue; } @@ -1109,8 +1110,16 @@ mod tests { "loader/entries/random_file.txt", "Random file that we won't parse", )?; - tempdir.atomic_write("loader/entries/entry1.conf", entry1)?; - tempdir.atomic_write("loader/entries/entry2.conf", entry2)?; + tempdir.atomic_write( + "loader/entries/random_file.conf", + "Random file that we won't parse", + )?; + tempdir.atomic_write( + "loader/entries/bootc_random_file.txt", + "Random file that we won't parse", + )?; + tempdir.atomic_write("loader/entries/bootc_entry1.conf", entry1)?; + tempdir.atomic_write("loader/entries/bootc_entry2.conf", entry2)?; let result = get_sorted_type1_boot_entries_helper(&tempdir, true, false, Bootloader::Systemd) @@ -1272,8 +1281,8 @@ mod tests { tempdir.create_dir_all("loader/entries")?; tempdir.create_dir_all("loader/entries.staged")?; - tempdir.atomic_write("loader/entries/active.conf", active_entry)?; - tempdir.atomic_write("loader/entries.staged/staged.conf", staged_entry)?; + tempdir.atomic_write("loader/entries/bootc_active.conf", active_entry)?; + tempdir.atomic_write("loader/entries.staged/bootc_staged.conf", staged_entry)?; let result = list_type1_entries(&tempdir)?; assert_eq!(result.len(), 2); @@ -1310,7 +1319,7 @@ mod tests { let entry2 = format!( r#" - title Fedora Linux (2.0.0) + title Fedora Linux (2.0.0) version 2.0.0 sort-key {} linux /boot/vmlinuz diff --git a/crates/lib/src/composefs_consts.rs b/crates/lib/src/composefs_consts.rs index 8617f1005..d53255572 100644 --- a/crates/lib/src/composefs_consts.rs +++ b/crates/lib/src/composefs_consts.rs @@ -48,6 +48,9 @@ pub(crate) const TYPE1_BOOT_DIR_PREFIX: &str = "bootc_composefs-"; /// The prefix for names of UKI and UKI Addons pub(crate) const UKI_NAME_PREFIX: &str = TYPE1_BOOT_DIR_PREFIX; +/// The prefix for BLS file entries +pub(crate) const BLS_ENTRY_PREFIX: &str = "bootc_"; + /// Prefix for OCI tags owned by bootc in the composefs repository. /// /// Tags are created as `localhost/bootc-` to act as GC roots diff --git a/tmt/tests/booted/test-composefs-corruped-state-resilience.nu b/tmt/tests/booted/test-composefs-corruped-state-resilience.nu index cbd10f67b..943f2a681 100644 --- a/tmt/tests/booted/test-composefs-corruped-state-resilience.nu +++ b/tmt/tests/booted/test-composefs-corruped-state-resilience.nu @@ -41,9 +41,9 @@ def first_boot [] { systemd-run -p MountFlags=slave -qdPG -- /bin/sh -c $" mount -orw,remount /sysroot cd ($entries_dir) - cp * new-entry.conf - - sed -i 's;($booted_verity);bad-verity;' new-entry.conf + cp * bootc_new-entry.conf + + sed -i 's;($booted_verity);bad-verity;' bootc_new-entry.conf " # This should work but log a warning in journal @@ -76,8 +76,8 @@ def first_boot [] { # Test the same thing but with an existing rollback deployment def second_boot [] { assert equal $booted.image.image "localhost/bootc-test-1" - - # Create another derived image + + # Create another derived image tap make_uki_containerfile $" FROM localhost/bootc as base RUN echo 'second-deployment' > /usr/share/deployment-marker From d1918cda644429457a618914683ec28883540fec Mon Sep 17 00:00:00 2001 From: Dudecake Date: Wed, 10 Jun 2026 12:37:32 +0000 Subject: [PATCH 2/3] Copy unmanaged BLS entries to staging dir on upgrade --- .../backwards_compat/bcompat_boot.rs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/crates/lib/src/bootc_composefs/backwards_compat/bcompat_boot.rs b/crates/lib/src/bootc_composefs/backwards_compat/bcompat_boot.rs index bf203c0d4..afba88759 100644 --- a/crates/lib/src/bootc_composefs/backwards_compat/bcompat_boot.rs +++ b/crates/lib/src/bootc_composefs/backwards_compat/bcompat_boot.rs @@ -15,6 +15,7 @@ use crate::{ composefs_consts::{ ORIGIN_KEY_BOOT, ORIGIN_KEY_BOOT_TYPE, STATE_DIR_RELATIVE, TYPE1_BOOT_DIR_PREFIX, TYPE1_ENT_PATH_STAGED, UKI_NAME_PREFIX, USER_CFG_STAGED, + TYPE1_ENT_PATH, BLS_ENTRY_PREFIX, }, parsers::bls_config::{BLSConfig, BLSConfigType, EFIKey}, spec::BootloaderKind, @@ -244,6 +245,15 @@ fn create_staged_bls_entries(boot_dir: &Dir, entries: &Vec<(String, BLSConfig)>) staged_entries.atomic_write(filename, new_entry.to_string().as_bytes())?; } + let original_entries = boot_dir.open_dir(TYPE1_ENT_PATH)?; + for entry in original_entries.entries_utf8()? { + let entry = entry?; + let entry_name = entry.file_name()?; + if entry.file_type()?.is_file() && !entry_name.starts_with(BLS_ENTRY_PREFIX) { + original_entries.copy(entry_name.clone(), &staged_entries, entry_name).context("Staging non-managed BLS entry")?; + } + } + fsync(staged_entries.reopen_as_ownedfd()?).context("fsync") } @@ -396,3 +406,58 @@ pub(crate) async fn prepend_custom_prefix( Ok(()) } + +#[cfg(test)] +mod tests { + use anyhow::Result; + use cap_std_ext::{cap_std, dirext::CapStdExtDirExt}; + use crate::bootc_composefs::backwards_compat::bcompat_boot::*; + use crate::parsers::bls_config::parse_bls_config; + + #[test] + fn test_create_staged_bls_entries() -> Result<()> { + let tempdir = cap_std_ext::cap_tempfile::tempdir(cap_std::ambient_authority())?; + + let entry1 = r#" + title Fedora 42.20250623.3.1 (CoreOS) + version fedora-42.0 + sort-key 1 + linux /boot/7e11ac46e3e022053e7226a20104ac656bf72d1a84e3a398b7cce70e9df188b6/vmlinuz-5.14.10 + initrd /boot/7e11ac46e3e022053e7226a20104ac656bf72d1a84e3a398b7cce70e9df188b6/initramfs-5.14.10.img + options root=UUID=abc123 rw composefs=7e11ac46e3e022053e7226a20104ac656bf72d1a84e3a398b7cce70e9df188b6 + "#; + let entry2 = r#" + title Fedora 41.20250214.2.0 (CoreOS) + version fedora-42.0 + sort-key 2 + efi /EFI/Linux/f7415d75017a12a387a39d2281e033a288fc15775108250ef70a01dcadb93346.efi + options root=UUID=abc123 rw composefs=febdf62805de2ae7b6b597f2a9775d9c8a753ba1e5f09298fc8fbe0b0d13bf01 + "#; + let entry3 = r#" + title Test + version 1 + sort-key 9 + efi /EFI/boot/test.efi + "#; + + tempdir.create_dir_all("loader/entries")?; + tempdir.atomic_write("loader/entries/bootc_entry1.conf", entry1)?; + tempdir.atomic_write("loader/entries/bootc_entry2.conf", entry2)?; + tempdir.atomic_write("loader/entries/entry3.conf", entry3)?; + + let entries = vec![ + ("bootc_entry1.conf".to_string(), parse_bls_config(entry1).unwrap()), + ("bootc_entry2.conf".to_string(), parse_bls_config(entry2).unwrap()), + ]; + + create_staged_bls_entries(&tempdir, &entries).unwrap(); + + assert!(tempdir.exists("loader/entries.staged/bootc_entry1.conf")); + assert!(tempdir.exists("loader/entries.staged/bootc_entry2.conf")); + assert!(tempdir.exists("loader/entries.staged/entry3.conf")); + + assert_eq!(str::from_utf8(&tempdir.read("loader/entries.staged/entry3.conf")?[..])?, entry3); + + Ok(()) + } +} From 6307167ff3d712bca4ee76a077324b0025a7c14c Mon Sep 17 00:00:00 2001 From: Dudecake Date: Wed, 10 Jun 2026 12:37:32 +0000 Subject: [PATCH 3/3] Added tests for non-confirming efi BLS entries --- crates/lib/src/parsers/bls_config.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/crates/lib/src/parsers/bls_config.rs b/crates/lib/src/parsers/bls_config.rs index 1de39e4be..49ce2b70f 100644 --- a/crates/lib/src/parsers/bls_config.rs +++ b/crates/lib/src/parsers/bls_config.rs @@ -868,6 +868,34 @@ mod tests { Ok(()) } + #[test] + fn test_boot_artifact_verity_efi_no_prefix() -> Result<()> { + let input = r#" + title Test + version 1 + efi /EFI/boot/test.efi + "#; + let config = parse_bls_config(&input)?; + + let result = config.get_verity(); + assert!(result.is_err()); + Ok(()) + } + + #[test] + fn test_boot_artifact_verity_efi_no_extension() -> Result<()> { + let input = r#" + title Test + version 1 + efi /EFI/boot/test + "#; + let config = parse_bls_config(&input)?; + + let result = config.get_verity(); + assert!(result.is_err()); + Ok(()) + } + /// Test that Non-EFI boot_artifact_name fails when linux path has no parent #[test] fn test_boot_artifact_name_non_efi_no_parent() {