Skip to content

Commit ce8443a

Browse files
ukify: Allow passing custom kernel, initramfs
While building a sealed UKI image we'd want to remove the original kernel + initramfs from the final image and have only the final UKI present. This was not possible before as `bootc container ukify` expected kernel + initramfs to be present in `usr/lib/modules` of container root Fixes: #2185 Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com> wip
1 parent 07735ee commit ce8443a

3 files changed

Lines changed: 81 additions & 18 deletions

File tree

crates/lib/src/cli.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,19 @@ pub(crate) enum ContainerOpts {
442442
#[clap(long)]
443443
write_dumpfile_to: Option<Utf8PathBuf>,
444444

445+
/// The kernel version.
446+
/// Required if kernel is passed
447+
#[clap(long, requires = "kernel")]
448+
kver: Option<String>,
449+
450+
/// Path to the kernel
451+
#[clap(long, requires = "initramfs", requires = "kver")]
452+
kernel: Option<Utf8PathBuf>,
453+
454+
/// Path to the initramfs
455+
#[clap(long, requires = "kernel")]
456+
initramfs: Option<Utf8PathBuf>,
457+
445458
/// Additional arguments to pass to ukify (after `--`).
446459
#[clap(last = true)]
447460
args: Vec<OsString>,
@@ -1893,12 +1906,32 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
18931906
kargs,
18941907
allow_missing_verity,
18951908
write_dumpfile_to,
1909+
kernel,
1910+
kver,
1911+
initramfs,
18961912
args,
18971913
} => {
1914+
let kernel = match (kernel, initramfs) {
1915+
(Some(path), Some(initramfs)) => Some(crate::kernel::KernelInternal {
1916+
kernel: crate::kernel::Kernel {
1917+
unified: false,
1918+
version: kver
1919+
.ok_or_else(|| anyhow::anyhow!("Expected kver to be present"))?,
1920+
},
1921+
k_type: crate::kernel::KernelType::Vmlinuz { path, initramfs },
1922+
}),
1923+
1924+
(None, None) => None,
1925+
1926+
// Shouldn't happen due to clap constraints but for sanity
1927+
_ => anyhow::bail!("--kernel and --initramfs must be provided together"),
1928+
};
1929+
18981930
crate::ukify::build_ukify(
18991931
&rootfs,
19001932
&kargs,
19011933
&args,
1934+
kernel,
19021935
allow_missing_verity,
19031936
write_dumpfile_to.as_deref(),
19041937
)

crates/lib/src/ukify.rs

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use fn_error_context::context;
1515

1616
use crate::bootc_composefs::digest::compute_composefs_digest;
1717
use crate::bootc_composefs::status::ComposefsCmdline;
18+
use crate::kernel::KernelInternal;
1819

1920
/// Build a UKI from the given rootfs.
2021
///
@@ -30,6 +31,7 @@ pub(crate) async fn build_ukify(
3031
rootfs: &Utf8Path,
3132
extra_kargs: &[String],
3233
args: &[OsString],
34+
kernel: Option<KernelInternal>,
3335
allow_missing_fsverity: bool,
3436
write_dumpfile_to: Option<&Utf8Path>,
3537
) -> Result<()> {
@@ -52,30 +54,46 @@ pub(crate) async fn build_ukify(
5254
let root = Dir::open_ambient_dir(rootfs, cap_std_ext::cap_std::ambient_authority())
5355
.with_context(|| format!("Opening rootfs {rootfs}"))?;
5456

55-
// Find the kernel
56-
let kernel = crate::kernel::find_kernel(&root)?
57-
.ok_or_else(|| anyhow::anyhow!("No kernel found in {rootfs}"))?;
57+
let kernel_final = match kernel {
58+
Some(ref kernel) => kernel,
59+
None => &crate::kernel::find_kernel(&root)?
60+
.ok_or_else(|| anyhow::anyhow!("No kernel found in {rootfs}"))?,
61+
};
5862

5963
// Extract vmlinuz and initramfs paths, or bail if this is already a UKI
60-
let (vmlinuz_path, initramfs_path) = match kernel.k_type {
64+
let (vmlinuz_path, initramfs_path) = match &kernel_final.k_type {
6165
crate::kernel::KernelType::Vmlinuz { path, initramfs } => (path, initramfs),
6266
crate::kernel::KernelType::Uki { path, .. } => {
6367
anyhow::bail!("Cannot build UKI: rootfs already contains a UKI at {path}");
6468
}
6569
};
6670

6771
// Verify kernel and initramfs exist
68-
if !root
69-
.try_exists(&vmlinuz_path)
70-
.context("Checking for vmlinuz")?
71-
{
72-
anyhow::bail!("Kernel not found at {vmlinuz_path}");
73-
}
74-
if !root
75-
.try_exists(&initramfs_path)
76-
.context("Checking for initramfs")?
77-
{
78-
anyhow::bail!("Initramfs not found at {initramfs_path}");
72+
//
73+
// NOTE: Not using cap_std here as the vmlinuz/initramfs path from
74+
// args can be outside of "rootfs"
75+
if kernel.is_some() {
76+
if !vmlinuz_path.exists() {
77+
anyhow::bail!("Kernel not found at {vmlinuz_path}");
78+
}
79+
80+
if !initramfs_path.exists() {
81+
anyhow::bail!("Initramfs not found at {initramfs_path}");
82+
}
83+
} else {
84+
if !root
85+
.try_exists(&vmlinuz_path)
86+
.context("Checking for vmlinuz")?
87+
{
88+
anyhow::bail!("Kernel not found at {vmlinuz_path}");
89+
}
90+
91+
if !root
92+
.try_exists(&initramfs_path)
93+
.context("Checking for initramfs")?
94+
{
95+
anyhow::bail!("Initramfs not found at {initramfs_path}");
96+
}
7997
}
8098

8199
// Compute the composefs digest
@@ -105,7 +123,7 @@ pub(crate) async fn build_ukify(
105123
.arg("--initrd")
106124
.arg(&initramfs_path)
107125
.arg("--uname")
108-
.arg(&kernel.kernel.version)
126+
.arg(&kernel_final.kernel.version)
109127
.arg("--cmdline")
110128
.arg(&cmdline_str)
111129
.arg("--os-release")
@@ -132,7 +150,7 @@ mod tests {
132150
let tempdir = tempfile::tempdir().unwrap();
133151
let path = Utf8Path::from_path(tempdir.path()).unwrap();
134152

135-
let result = build_ukify(path, &[], &[], false, None).await;
153+
let result = build_ukify(path, &[], &[], None, false, None).await;
136154
assert!(result.is_err());
137155
let err = format!("{:#}", result.unwrap_err());
138156
assert!(
@@ -150,7 +168,7 @@ mod tests {
150168
fs::create_dir_all(tempdir.path().join("boot/EFI/Linux")).unwrap();
151169
fs::write(tempdir.path().join("boot/EFI/Linux/test.efi"), b"fake uki").unwrap();
152170

153-
let result = build_ukify(path, &[], &[], false, None).await;
171+
let result = build_ukify(path, &[], &[], None, false, None).await;
154172
assert!(result.is_err());
155173
let err = format!("{:#}", result.unwrap_err());
156174
assert!(

docs/src/man/bootc-container-ukify.8.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ Any additional arguments after `--` are passed through to ukify unchanged.
3535

3636
Write a dumpfile to this path
3737

38+
**--kver**=*KVER*
39+
40+
The kernel version. Required if kernel is passed
41+
42+
**--kernel**=*KERNEL*
43+
44+
Path to the kernel
45+
46+
**--initramfs**=*INITRAMFS*
47+
48+
Path to the initramfs
49+
3850
<!-- END GENERATED OPTIONS -->
3951

4052
# EXAMPLES

0 commit comments

Comments
 (0)