Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ jobs:
# No fedora-44 due to https://bugzilla.redhat.com/show_bug.cgi?id=2429501
test_os: [fedora-43, centos-9, centos-10]
variant: [ostree, composefs-sealeduki-sdboot, composefs-sdboot, composefs-grub]
filesystem: ["ext4", "xfs"]
exclude:
# centos-9 UKI is experimental/broken (https://github.com/bootc-dev/bootc/issues/1812)
- test_os: centos-9
Expand All @@ -172,6 +173,10 @@ jobs:
variant: composefs-sdboot
- test_os: centos-9
variant: composefs-grub
# We only test filesystems for composefs to test if composefs backend will work on fs
# without fsverity
- variant: ostree
filesystem: ext4

runs-on: ubuntu-24.04

Expand All @@ -190,6 +195,7 @@ jobs:
echo "BOOTC_base=${BASE}" >> $GITHUB_ENV
echo "RUST_BACKTRACE=full" >> $GITHUB_ENV
echo "RUST_LOG=trace" >> $GITHUB_ENV
echo "BOOTC_filesystem=${{ matrix.filesystem }}" >> $GITHUB_ENV

case "${{ matrix.variant }}" in
composefs-grub)
Expand All @@ -213,8 +219,6 @@ jobs:
;;
esac



if [ "${{ matrix.variant }}" = "composefs-sealeduki-sdboot" ]; then
BUILDROOTBASE=$(just pullspec-for-os buildroot-base ${{ matrix.test_os }})
echo "BOOTC_buildroot_base=${BUILDROOTBASE}" >> $GITHUB_ENV
Expand Down Expand Up @@ -244,7 +248,7 @@ jobs:
- name: Run TMT integration tests
run: |
if [[ "${{ matrix.variant }}" = composefs* ]]; then
just "test-${{ matrix.variant }}"
just "test-${{ matrix.variant }}" "${{ matrix.filesystem }}"
else
just test-tmt integration
fi
Expand All @@ -255,7 +259,7 @@ jobs:
if: always()
uses: actions/upload-artifact@v6
with:
name: tmt-log-PR-${{ github.event.number }}-${{ matrix.test_os }}-${{ matrix.variant }}-${{ env.ARCH }}
name: tmt-log-PR-${{ github.event.number }}-${{ matrix.test_os }}-${{ matrix.variant }}-${{ matrix.filesystem }}-${{ env.ARCH }}
path: /var/tmp/tmt

# Test bootc install on Fedora CoreOS (separate job to avoid disk space issues
Expand Down
10 changes: 9 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp
# We need our newly-built bootc for the compute-composefs-digest command
FROM tools as sealed-uki
ARG variant
ARG filesystem
# Install our bootc package (only needed for the compute-composefs-digest command)
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=bind,from=packages,src=/,target=/run/packages \
Expand All @@ -186,8 +187,15 @@ RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp
--mount=type=bind,from=packaging,src=/,target=/run/packaging \
--mount=type=bind,from=base-penultimate,src=/,target=/run/target <<EORUN
set -xeuo pipefail

allow_missing_verity=false

if [[ filesystem == "xfs" ]]; then
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, this is completely wrong. I was wondering how the sealed xfs test passed

allow_missing_verity=true
fi

if test "${variant}" = "composefs-sealeduki-sdboot"; then
/run/packaging/seal-uki /run/target /out /run/secrets
/run/packaging/seal-uki /run/target /out /run/secrets $allow_missing_verity
fi
EORUN

Expand Down
29 changes: 19 additions & 10 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ upgrade_img := base_img + "-upgrade"
# Build variant: ostree (default) or composefs-sealeduki-sdboot (sealed UKI)
variant := env("BOOTC_variant", "ostree")
bootloader := env("BOOTC_bootloader", "grub")
# Only used for composefs tests
filesystem := env("BOOTC_filesystem", "ext4")
# Base container image to build from
base := env("BOOTC_base", "quay.io/centos-bootc/centos-bootc:stream10")
# Buildroot base image
Expand All @@ -39,7 +41,11 @@ lbi_images := "quay.io/curl/curl:latest quay.io/curl/curl-base:latest registry.a
fedora-coreos := "quay.io/fedora/fedora-coreos:testing-devel"
generic_buildargs := ""
_extra_src_args := if extra_src != "" { "-v " + extra_src + ":/run/extra-src:ro --security-opt=label=disable" } else { "" }
base_buildargs := generic_buildargs + " " + _extra_src_args + " --build-arg=base=" + base + " --build-arg=variant=" + variant + " --build-arg=bootloader=" + bootloader
base_buildargs := generic_buildargs + " " + _extra_src_args \
+ " --build-arg=base=" + base \
+ " --build-arg=variant=" + variant \
+ " --build-arg=bootloader=" + bootloader \
+ " --build-arg=filesystem=" + filesystem # required for bootc container ukify to allow missing fsverity
buildargs := base_buildargs \
+ " --cap-add=all --security-opt=label=type:container_runtime_t --device /dev/fuse" \
+ " --secret=id=secureboot_key,src=target/test-secureboot/db.key --secret=id=secureboot_cert,src=target/test-secureboot/db.crt"
Expand Down Expand Up @@ -106,23 +112,26 @@ test-container: build build-units

# Build and test sealed composefs images
[group('core')]
test-composefs-sealeduki-sdboot:
just variant=composefs-sealeduki-sdboot test-tmt readonly local-upgrade-reboot
test-composefs-sealeduki-sdboot filesystem:
just variant=composefs-sealeduki-sdboot filesystem={{filesystem}} test-tmt readonly local-upgrade-reboot

[group('core')]
test-composefs bootloader:
just variant=composefs bootloader={{bootloader}} \
test-tmt --composefs-backend --bootloader {{bootloader}} integration
test-composefs bootloader filesystem:
just variant=composefs bootloader={{bootloader}} filesystem={{filesystem}} \
test-tmt --composefs-backend \
--bootloader {{bootloader}} \
--filesystem {{filesystem}} \
integration

# Build and test composefs images booted using Type1 boot entries and systemd-boot as the bootloader
[group('core')]
test-composefs-sdboot:
just test-composefs systemd
test-composefs-sdboot filesystem:
just test-composefs systemd {{filesystem}}

# Build and test composefs images booted using Type1 boot entries and grub as the bootloader
[group('core')]
test-composefs-grub:
just test-composefs grub
test-composefs-grub filesystem:
just test-composefs grub {{filesystem}}

# Run cargo fmt and clippy checks in container
[group('core')]
Expand Down
10 changes: 9 additions & 1 deletion contrib/packaging/seal-uki
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ shift
# Path to secrets directory
secrets=$1
shift
allow_missing_verity=$1
shift

# Find the kernel version (needed for output filename)
kver=$(bootc container inspect --rootfs "${target}" --json | jq -r '.kernel.version')
Expand Down Expand Up @@ -38,6 +40,12 @@ containerukifyargs=(--rootfs "${target}")
# See https://github.com/bootc-dev/bootc/issues/1826
containerukifyargs+=(--karg enforcing=0)

missing_verity=()

if [[ $allow_missing_verity == "true" ]]; then
missing_verity+=(--allow-missing-verity)
fi

# Build the UKI using bootc container ukify
# This computes the composefs digest, reads kargs from kargs.d, and invokes ukify
bootc container ukify "${containerukifyargs[@]}" -- "${ukifyargs[@]}"
bootc container ukify "${containerukifyargs[@]}" "${missing_verity[@]}" -- "${ukifyargs[@]}"
14 changes: 9 additions & 5 deletions crates/initramfs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,17 @@ fn open_root_fs(path: &Path) -> Result<OwnedFd> {
/// Prepares a floating mount for composefs and returns the fd
///
/// # Arguments
/// * sysroot - fd for /sysroot
/// * name - Name of the EROFS image to be mounted
/// * insecure - Whether fsverity is optional or not
/// * sysroot - fd for /sysroot
/// * name - Name of the EROFS image to be mounted
/// * allow_missing_fsverity - Whether to allow mount without fsverity support
#[context("Mounting composefs image")]
pub fn mount_composefs_image(sysroot: &OwnedFd, name: &str, insecure: bool) -> Result<OwnedFd> {
pub fn mount_composefs_image(
sysroot: &OwnedFd,
name: &str,
allow_missing_fsverity: bool,
) -> Result<OwnedFd> {
let mut repo = Repository::<Sha512HashValue>::open_path(sysroot, "composefs")?;
repo.set_insecure(insecure);
repo.set_insecure(allow_missing_fsverity);
let rootfs = repo
.mount(name)
.context("Failed to mount composefs image")?;
Expand Down
53 changes: 36 additions & 17 deletions crates/lib/src/bootc_composefs/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::parsers::bls_config::{BLSConfig, BLSConfigType};
use crate::parsers::grub_menuconfig::MenuEntry;
use crate::task::Task;
use crate::{
bootc_composefs::repo::get_imgref,
Expand All @@ -119,6 +118,7 @@ use crate::{
},
spec::{Bootloader, Host},
};
use crate::{parsers::grub_menuconfig::MenuEntry, store::BootedComposefs};

use crate::install::{RootSetup, State};

Expand Down Expand Up @@ -155,7 +155,14 @@ pub(crate) enum BootSetupType<'a> {
),
),
/// For `bootc upgrade`
Upgrade((&'a Storage, &'a ComposefsFilesystem, &'a Host)),
Upgrade(
(
&'a Storage,
&'a BootedComposefs,
&'a ComposefsFilesystem,
&'a Host,
),
),
}

#[derive(
Expand Down Expand Up @@ -512,7 +519,7 @@ pub(crate) fn setup_composefs_bls_boot(

cmdline_options.extend(&root_setup.kargs);

let composefs_cmdline = if state.composefs_options.insecure {
let composefs_cmdline = if state.composefs_options.allow_missing_verity {
format!("{COMPOSEFS_CMDLINE}=?{id_hex}")
} else {
format!("{COMPOSEFS_CMDLINE}={id_hex}")
Expand All @@ -532,7 +539,7 @@ pub(crate) fn setup_composefs_bls_boot(
)
}

BootSetupType::Upgrade((storage, fs, host)) => {
BootSetupType::Upgrade((storage, booted_cfs, fs, host)) => {
let sysroot_parent = get_sysroot_parent_dev(&storage.physical_root)?;
let bootloader = host.require_composefs_booted()?.bootloader.clone();

Expand All @@ -551,7 +558,12 @@ pub(crate) fn setup_composefs_bls_boot(
};

// Copy all cmdline args, replacing only `composefs=`
let param = format!("{COMPOSEFS_CMDLINE}={id_hex}");
let param = if booted_cfs.cmdline.allow_missing_fsverity {
format!("{COMPOSEFS_CMDLINE}=?{id_hex}")
} else {
format!("{COMPOSEFS_CMDLINE}={id_hex}")
};

let param =
Parameter::parse(&param).context("Failed to create 'composefs=' parameter")?;
cmdline.add_or_modify(&param);
Expand Down Expand Up @@ -797,7 +809,7 @@ fn write_pe_to_esp(
file_path: &Utf8Path,
pe_type: PEType,
uki_id: &Sha512HashValue,
is_insecure_from_opts: bool,
missing_fsverity_allowed: bool,
mounted_efi: impl AsRef<Path>,
bootloader: &Bootloader,
) -> Result<Option<UKIInfo>> {
Expand All @@ -810,17 +822,19 @@ fn write_pe_to_esp(
if matches!(pe_type, PEType::Uki) {
let cmdline = uki::get_cmdline(&efi_bin).context("Getting UKI cmdline")?;

let (composefs_cmdline, insecure) =
let (composefs_cmdline, missing_verity_allowed_cmdline) =
get_cmdline_composefs::<Sha512HashValue>(cmdline).context("Parsing composefs=")?;

// If the UKI cmdline does not match what the user has passed as cmdline option
// NOTE: This will only be checked for new installs and now upgrades/switches
match is_insecure_from_opts {
true if !insecure => {
tracing::warn!("--insecure passed as option but UKI cmdline does not support it");
match missing_fsverity_allowed {
true if !missing_verity_allowed_cmdline => {
tracing::warn!(
"--allow-missing-fsverity passed as option but UKI cmdline does not support it"
);
}

false if insecure => {
false if missing_verity_allowed_cmdline => {
tracing::warn!("UKI cmdline has composefs set as insecure");
}

Expand Down Expand Up @@ -1065,7 +1079,8 @@ pub(crate) fn setup_composefs_uki_boot(
id: &Sha512HashValue,
entries: Vec<ComposefsBootEntry<Sha512HashValue>>,
) -> Result<String> {
let (root_path, esp_device, bootloader, is_insecure_from_opts, uki_addons) = match setup_type {
let (root_path, esp_device, bootloader, missing_fsverity_allowed, uki_addons) = match setup_type
{
BootSetupType::Setup((root_setup, state, postfetch, ..)) => {
state.require_no_kargs_for_uki()?;

Expand All @@ -1075,12 +1090,12 @@ pub(crate) fn setup_composefs_uki_boot(
root_setup.physical_root_path.clone(),
esp_part.node.clone(),
postfetch.detected_bootloader.clone(),
state.composefs_options.insecure,
state.composefs_options.allow_missing_verity,
state.composefs_options.uki_addon.as_ref(),
)
}

BootSetupType::Upgrade((storage, _, host)) => {
BootSetupType::Upgrade((storage, booted_cfs, _, host)) => {
let sysroot = Utf8PathBuf::from("/sysroot"); // Still needed for root_path
let sysroot_parent = get_sysroot_parent_dev(&storage.physical_root)?;
let bootloader = host.require_composefs_booted()?.bootloader.clone();
Expand All @@ -1089,7 +1104,7 @@ pub(crate) fn setup_composefs_uki_boot(
sysroot,
get_esp_partition(&sysroot_parent)?.0,
bootloader,
false,
booted_cfs.cmdline.allow_missing_fsverity,
None,
)
}
Expand Down Expand Up @@ -1140,7 +1155,7 @@ pub(crate) fn setup_composefs_uki_boot(
utf8_file_path,
entry.pe_type,
&id,
is_insecure_from_opts,
missing_fsverity_allowed,
esp_mount.dir.path(),
&bootloader,
)?;
Expand Down Expand Up @@ -1219,8 +1234,11 @@ pub(crate) async fn setup_composefs_boot(
root_setup: &RootSetup,
state: &State,
image_id: &str,
allow_missing_fsverity: bool,
) -> Result<()> {
let repo = open_composefs_repo(&root_setup.physical_root)?;
let mut repo = open_composefs_repo(&root_setup.physical_root)?;
repo.set_insecure(allow_missing_fsverity);

let mut fs = create_composefs_filesystem(&repo, image_id, None)?;
let entries = fs.transform_for_boot(&repo)?;
let id = fs.commit_image(&repo, None)?;
Expand Down Expand Up @@ -1291,6 +1309,7 @@ pub(crate) async fn setup_composefs_boot(
&state.source.imageref.name,
))
.await?,
allow_missing_fsverity,
)
.await?;

Expand Down
12 changes: 10 additions & 2 deletions crates/lib/src/bootc_composefs/finalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ pub(crate) async fn get_etc_diff(storage: &Storage, booted_cfs: &BootedComposefs

// Mount the booted EROFS image to get pristine etc
let sysroot_fd = storage.physical_root.reopen_as_ownedfd()?;
let composefs_fd = mount_composefs_image(&sysroot_fd, &booted_composefs.verity, false)?;
let composefs_fd = mount_composefs_image(
&sysroot_fd,
&booted_composefs.verity,
booted_cfs.cmdline.allow_missing_fsverity,
)?;

let erofs_tmp_mnt = TempMount::mount_fd(&composefs_fd)?;

Expand Down Expand Up @@ -68,7 +72,11 @@ pub(crate) async fn composefs_backend_finalize(

// Mount the booted EROFS image to get pristine etc
let sysroot_fd = storage.physical_root.reopen_as_ownedfd()?;
let composefs_fd = mount_composefs_image(&sysroot_fd, &booted_composefs.verity, false)?;
let composefs_fd = mount_composefs_image(
&sysroot_fd,
&booted_composefs.verity,
booted_cfs.cmdline.allow_missing_fsverity,
)?;

let erofs_tmp_mnt = TempMount::mount_fd(&composefs_fd)?;

Expand Down
Loading
Loading