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
46 changes: 38 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ RUN --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
# Install systemd-ukify and systemd-boot for UKIs
# This also installs systemd-boot for the grub UKI case which is not ideal...
if [[ "${boot_type}" == "uki" ]]; then
pkgs_to_install+=(systemd-ukify)
pkgs_to_install+=(systemd-ukify binutils)
fi

if [[ ${#pkgs_to_install[@]} -gt 0 ]]; then
Expand Down Expand Up @@ -135,7 +135,10 @@ ARG pkgversion
ARG SOURCE_DATE_EPOCH
ENV SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH}
# Build RPM directly from source, using cached target directory
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp --mount=type=cache,target=/src/target --mount=type=cache,target=/var/roothome RPM_VERSION="${pkgversion}" /src/contrib/packaging/build-rpm
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=cache,target=/src/target \
--mount=type=cache,target=/var/roothome \
RPM_VERSION="${pkgversion}" /src/contrib/packaging/build-rpm

# Build a systemd-sysext containing just the bootc binary.
# Skips RPM machinery entirely for fast incremental rebuilds.
Expand Down Expand Up @@ -218,7 +221,7 @@ COPY --from=update-generated-from-code /src/docs/src/*.schema.json /docs/src/
# ----

# Perform all filesystem transformations except generating the sealed UKI (if configured)
FROM base as base-penultimate
FROM base as base-penultimate-source
ARG variant
ARG bootloader
ARG boot_type
Expand Down Expand Up @@ -246,6 +249,10 @@ rm -rf /var/cache
rm -rf /run/rhsm

EORUN

FROM base-penultimate-source as base-penultimate
ARG boot_type

# Configure the rootfs
ARG rootfs=""
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
Expand All @@ -260,9 +267,19 @@ RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp
COPY --from=packaging /usr-extras/ /usr/
# Clean up package manager caches
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-source,src=/,target=/run/base-penultimate-src \
--mount=type=bind,from=packaging,src=/,target=/run/packaging <<EORUN
/run/packaging/cleanup

# Remove kernel + initrd if UKI
if [[ "${boot_type}" == "uki" ]]; then
kver=$(bootc container inspect --rootfs /run/base-penultimate-src --json | jq -r '.kernel.version')

rm -v "/usr/lib/modules/$kver/vmlinuz"
rm -v "/usr/lib/modules/$kver/initramfs.img"
fi
EORUN

# Generate the sealed UKI in a separate stage
# This computes the composefs digest from base-penultimate and creates a signed UKI
# We need our newly-built bootc for the compute-composefs-digest command
Expand All @@ -278,18 +295,29 @@ RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=secret,id=secureboot_key \
--mount=type=secret,id=secureboot_cert \
--mount=type=bind,from=base-penultimate-source,src=/,target=/run/base-penultimate-src \
--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
allow_missing_verity=()

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

if test "${boot_type}" = "uki"; then
/run/packaging/seal-uki /run/target /out /run/secrets $allow_missing_verity $seal_state
kver=$(bootc container inspect --rootfs /run/base-penultimate-src --json | jq -r '.kernel.version')

/run/packaging/seal-uki \
--target /run/target \
--output /out \
--secrets /run/secrets \
"${allow_missing_verity[@]}" \
--kernel "/run/base-penultimate-src/usr/lib/modules/$kver/vmlinuz" \
--kver "$kver" \
--initramfs "/run/base-penultimate-src/usr/lib/modules/$kver/initramfs.img" \
--seal-state $seal_state
fi
EORUN

Expand All @@ -299,11 +327,13 @@ ARG variant
ARG boot_type
# Copy the sealed UKI and finalize the image (remove raw kernel, create symlinks)
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=bind,from=base-penultimate-source,src=/,target=/run/base-penultimate-src \
--mount=type=bind,from=packaging,src=/,target=/run/packaging \
--mount=type=bind,from=sealed-uki,src=/,target=/run/sealed-uki <<EORUN
set -xeuo pipefail
if test "${boot_type}" = "uki"; then
/run/packaging/finalize-uki /run/sealed-uki/out
kver=$(bootc container inspect --rootfs /run/base-penultimate-src --json | jq -r '.kernel.version')
/run/packaging/finalize-uki /run/sealed-uki/out "$kver"
fi
EORUN
# And finally, test our linting
Expand Down
15 changes: 2 additions & 13 deletions contrib/packaging/finalize-uki
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,8 @@ set -xeuo pipefail
# Path to directory containing the generated UKI
uki_src=$1
shift

# Find the kernel version from the current system
kver=$(bootc container inspect --json | jq -r '.kernel.version')
if [ -z "$kver" ] || [ "$kver" = "null" ]; then
echo "Error: No kernel found" >&2
exit 1
fi
kver=$1
shift

# Create the EFI directory structure
mkdir -p /boot/EFI/Linux
Expand All @@ -36,12 +31,6 @@ mkdir -p /boot/EFI/Linux
target=/boot/EFI/Linux/${kver}.efi
cp "${uki_src}/${kver}.efi" "${target}"

# Remove the raw kernel and initramfs since we're using a UKI now.
# NOTE: We intentionally keep these for now until bcvk is updated to extract
# kernel/initramfs from UKIs in subdirectories. Once bcvk PR #144 is fixed
# to look for .efi files in /usr/lib/modules/<kver>/, we can uncomment this.
# rm -v "/usr/lib/modules/${kver}/vmlinuz" "/usr/lib/modules/${kver}/initramfs.img"

# NOTE: We used to create a symlink from /usr/lib/modules/${kver}/${kver}.efi to the UKI
# for tooling compatibility. However, composefs-boot's find_uki_components() doesn't
# handle symlinks correctly and fails with "is not a regular file". The UKI is already
Expand Down
98 changes: 71 additions & 27 deletions contrib/packaging/seal-uki
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,82 @@
# Generate a sealed UKI with embedded composefs digest
set -xeuo pipefail

# Path to the desired root filesystem
target=$1
shift
# Write to this directory
output=$1
shift
# Path to secrets directory
secrets=$1
shift
allow_missing_verity=$1
shift
seal_state=$1
shift

if [[ $seal_state == "sealed" && $allow_missing_verity == "true" ]]; then
missing_verity=()

while [ ! -z "${1:-}" ]; do
case "$1" in
# Path to the desired root filesystem
"--target")
target="$2"
shift
shift
;;

# Write to this directory
"--output")
output="$2"
shift
shift
;;

# Path to secrets directory
"--secrets")
secrets="$2"
shift
shift
;;

"--allow-missing-verity")
missing_verity=(--allow-missing-verity)
shift
;;

"--seal-state")
seal_state="$2"
shift
shift
;;

# The kernel version
"--kver")
kver="$2"
shift
shift
;;

# Path to the kernel
"--kernel")
kernel="$2"
shift
shift
;;

# Path to the initrd
"--initramfs")
initramfs="$2"
shift
shift
;;

* )
echo "Argument $1 not understood"
exit 1
;;
esac
done

if [[ $seal_state == "sealed" && ${#missing_verity[@]} -gt 0 ]]; then
echo "Cannot have missing verity with sealed UKI" >&2
exit 1
fi

# Find the kernel version (needed for output filename)
kver=$(bootc container inspect --rootfs "${target}" --json | jq -r '.kernel.version')
if [ -z "$kver" ] || [ "$kver" = "null" ]; then
echo "Error: No kernel found" >&2
exit 1
if [[ -z $kernel || -z $initramfs || -z $kver ]]; then
echo "kernel, initramfs and kver are required" >&2
exit 1
fi

kernel_params=(--kernel "$kernel" --initramfs "$initramfs" --kver "$kver")

mkdir -p "${output}"

# Baseline ukify options
Expand All @@ -45,12 +95,6 @@ fi
# Baseline container ukify options
containerukifyargs=(--rootfs "${target}")

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[@]}" "${missing_verity[@]}" -- "${ukifyargs[@]}"
bootc container ukify "${containerukifyargs[@]}" "${kernel_params[@]}" "${missing_verity[@]}" -- "${ukifyargs[@]}"
33 changes: 33 additions & 0 deletions crates/lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,19 @@ pub(crate) enum ContainerOpts {
#[clap(long)]
write_dumpfile_to: Option<Utf8PathBuf>,

/// The kernel version.
/// Required if kernel is passed
#[clap(long, requires = "kernel")]
kver: Option<String>,

/// Path to the kernel
#[clap(long, requires = "initramfs", requires = "kver")]
kernel: Option<Utf8PathBuf>,

/// Path to the initramfs
#[clap(long, requires = "kernel")]
initramfs: Option<Utf8PathBuf>,

/// Additional arguments to pass to ukify (after `--`).
#[clap(last = true)]
args: Vec<OsString>,
Expand Down Expand Up @@ -1893,12 +1906,32 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
kargs,
allow_missing_verity,
write_dumpfile_to,
kernel,
kver,
initramfs,
args,
} => {
let kernel = match (kernel, initramfs) {
(Some(path), Some(initramfs)) => Some(crate::kernel::KernelInternal {
kernel: crate::kernel::Kernel {
unified: false,
version: kver
.ok_or_else(|| anyhow::anyhow!("Expected kver to be present"))?,
},
k_type: crate::kernel::KernelType::Vmlinuz { path, initramfs },
}),

(None, None) => None,

// Shouldn't happen due to clap constraints but for sanity
_ => anyhow::bail!("--kernel and --initramfs must be provided together"),
};

crate::ukify::build_ukify(
&rootfs,
&kargs,
&args,
kernel,
allow_missing_verity,
write_dumpfile_to.as_deref(),
)
Expand Down
Loading
Loading