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
5 changes: 1 addition & 4 deletions Dockerfile.cfsuki
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ RUN --mount=type=secret,id=key \
# Should be generated externally
test -n "${COMPOSEFS_FSVERITY}"

# Inject the composefs kernel argument and specify a root with the x86_64 DPS UUID.
# TODO: Discoverable partition fleshed out, or drop root UUID as systemd-stub extension
# TODO: https://github.com/containers/composefs-rs/issues/183
cmdline="composefs=${COMPOSEFS_FSVERITY} root=UUID=4f68bce3-e8cd-4db1-96e7-fbcaf984b709 console=ttyS0,115200n8 enforcing=0 rw"
cmdline="composefs=${COMPOSEFS_FSVERITY} console=ttyS0,115200n8 enforcing=0 rw"

# pesign uses NSS database so create it from input cert/key
mkdir pesign
Expand Down
1 change: 1 addition & 0 deletions crates/blockdev/src/blockdev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub struct Device {
// Filesystem-related properties
pub label: Option<String>,
pub fstype: Option<String>,
pub uuid: Option<String>,
pub path: Option<String>,
}

Expand Down
6 changes: 1 addition & 5 deletions crates/lib/src/bootc_composefs/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ use crate::{
BOOT_LOADER_ENTRIES, COMPOSEFS_CMDLINE, ORIGIN_KEY_BOOT, ORIGIN_KEY_BOOT_DIGEST,
STAGED_BOOT_LOADER_ENTRIES, STATE_DIR_ABS, USER_CFG, USER_CFG_STAGED,
},
discoverable_partition_specification::this_arch_root,
install::RW_KARG,
spec::{Bootloader, Host},
};
Expand Down Expand Up @@ -412,10 +411,7 @@ pub(crate) fn setup_composefs_bls_boot(
(
Utf8PathBuf::from("/sysroot"),
get_esp_partition(&sysroot_parent)?.0,
Cmdline::from(format!(
"root=UUID={} {RW_KARG} {COMPOSEFS_CMDLINE}={id_hex}",
this_arch_root()
)),
Cmdline::from(format!("{RW_KARG} {COMPOSEFS_CMDLINE}={id_hex}")),
fs,
bootloader,
)
Expand Down
18 changes: 12 additions & 6 deletions crates/lib/src/install/baseline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ pub(crate) const EFIPN_SIZE_MB: u32 = 512;
/// We need more space than ostree as we have UKIs and UKI addons
/// We might also need to store UKIs for pinned deployments
pub(crate) const CFS_EFIPN_SIZE_MB: u32 = 1024;
/// The GPT type for "linux"
pub(crate) const LINUX_PARTTYPE: &str = "0FC63DAF-8483-4772-8E79-3D69D8477DE4";
#[cfg(feature = "install-to-disk")]
pub(crate) const PREPBOOT_GUID: &str = "9E1A2D38-C612-4316-AA26-8B49521E5A8B";
#[cfg(feature = "install-to-disk")]
Expand Down Expand Up @@ -113,7 +111,8 @@ fn mkfs<'a>(
let devinfo = bootc_blockdev::list_dev(dev.into())?;
let size = ostree_ext::glib::format_size(devinfo.size);

let u = uuid::Uuid::parse_str(crate::discoverable_partition_specification::this_arch_root())?;
// Generate a random UUID for the filesystem
let u = uuid::Uuid::new_v4();

let mut t = Task::new(
&format!("Creating {label} filesystem ({fs}) on device {dev} (size={size})"),
Expand Down Expand Up @@ -315,9 +314,11 @@ pub(crate) fn install_create_rootfs(
let root_size = root_size
.map(|v| Cow::Owned(format!("size={v}MiB, ")))
.unwrap_or_else(|| Cow::Borrowed(""));
let rootpart_uuid =
uuid::Uuid::parse_str(crate::discoverable_partition_specification::this_arch_root())?;
writeln!(
&mut partitioning_buf,
r#"{root_size}type={LINUX_PARTTYPE}, name="root""#
r#"{root_size}type={rootpart_uuid}, name="root""#
)?;
tracing::debug!("Partitioning: {partitioning_buf}");
Task::new("Initializing partitions", "sfdisk")
Expand All @@ -336,9 +337,14 @@ pub(crate) fn install_create_rootfs(
let base_partitions = &bootc_blockdev::partitions_of(&devpath)?;

let root_partition = base_partitions.find_partno(rootpn)?;
if root_partition.parttype.as_str() != LINUX_PARTTYPE {
// Verify the partition type matches the DPS root partition type for this architecture
let expected_parttype = crate::discoverable_partition_specification::this_arch_root();
if !root_partition
.parttype
.eq_ignore_ascii_case(expected_parttype)
{
anyhow::bail!(
"root partition {partno} has type {}; expected {LINUX_PARTTYPE}",
"root partition {rootpn} has type {}; expected {expected_parttype}",
root_partition.parttype.as_str()
);
}
Expand Down
7 changes: 7 additions & 0 deletions crates/tests-integration/src/composefs_bcvk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ fn inner_tests() -> Vec<Trial> {

assert_eq!(verity_from_status.unwrap(), verity_from_cmdline);

// Verify that we booted via systemd-gpt-auto-generator by checking
// that /proc/cmdline does NOT contain a root= parameter
let has_root_param = cmdline.iter().any(|entry| {
entry.key() == "root".into()
});
assert!(!has_root_param, "Sealed composefs image should not have root= in kernel cmdline; systemd-gpt-auto-generator should discover the root partition via DPS");

Ok(())
})]
.into_iter()
Expand Down
13 changes: 13 additions & 0 deletions docs/src/man/bootc-install-to-disk.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ the container image, alongside any required system partitions such as
the EFI system partition. Use `install to-filesystem` for anything
more complex such as RAID, LVM, LUKS etc.

## Partitioning details

The default as of bootc 1.11 uses the [Discoverable Partitions Specification](https://uapi-group.org/specifications/specs/discoverable_partitions_specification/)
for the generated root filesystem, as well as any required system partitions
such as the EFI system partition.

Note that by default when used with "type 1" bootloader setups (i.e. non-UKI)
a kernel argument `root=UUID=<uuid of filesystem>` is injected by default.

When used with the composefs backend and UKIs, it's recommended that
a bootloader implementing the DPS specification is used and that the root
partition is auto-discovered.

# OPTIONS

<!-- BEGIN GENERATED OPTIONS -->
Expand Down
14 changes: 14 additions & 0 deletions tmt/tests/booted/readonly/030-test-composefs.nu
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,26 @@ use tap.nu

tap begin "composefs integration smoke test"

def parse_cmdline [] {
open /proc/cmdline | str trim | split row " "
}

# Detect composefs by checking if composefs field is present
let st = bootc status --json | from json
let is_composefs = ($st.status.booted.composefs? != null)
let expecting_composefs = ($env.BOOTC_variant? | default "" | find "composefs") != null
if $expecting_composefs {
assert $is_composefs
# When using systemd-boot with DPS (Discoverable Partition Specification),
# /proc/cmdline should NOT contain a root= parameter because systemd-gpt-auto-generator
# discovers the root partition automatically
# Note that there is `bootctl --json=pretty` but it doesn't actually output JSON
let bootctl_output = (bootctl)
if ($bootctl_output | str contains 'Product: systemd-boot') {
let cmdline = parse_cmdline
let has_root_param = ($cmdline | any { |param| $param | str starts-with 'root=' })
assert (not $has_root_param) "systemd-boot image should not have root= in kernel cmdline; systemd-gpt-auto-generator should discover the root partition via DPS"
}
}

if $is_composefs {
Expand Down