mirror of
https://github.com/containers/bootc.git
synced 2026-02-05 15:45:53 +01:00
install: Fix DPS support
This fixes bootc's use of the Discoverable Partition Specification (DPS) to properly support systemd-gpt-auto-generator. Previously, bootc was incorrectly setting filesystem UUIDs to the DPS partition type UUID value, which caused UUID collisions and prevented proper DPS functionality. It's still a TODO on our side to support systemd-repart in this flow. Note we go back to using random filesystem UUIDs with this, but per above we should likely reinitialize them on boot via repart. Note we remove root= parameter from kernel cmdline for composefs sealed images, allowing systemd-gpt-auto-generator to auto-discover the root partition and we test this. Fixes: #1771 Assisted-by: Claude Code (Sonnet 4.5) Signed-off-by: Colin Walters <walters@verbum.org>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>,
|
||||
}
|
||||
|
||||
|
||||
@@ -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},
|
||||
};
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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")]
|
||||
@@ -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})"),
|
||||
@@ -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")
|
||||
@@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user