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
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions contrib/packaging/bcvk.spec
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@ Requires: podman
Requires: qemu-img
Requires: qemu-kvm
Requires: virtiofsd
# Extraction and initramfs tools are needed for some ephemeral boot images.
Recommends: binutils
# Initramfs tools are needed for some ephemeral boot images.
Recommends: kernel-tools
Recommends: android-tools
# libvirt-client is optional but recommended for 'bcvk libvirt' commands
Recommends: libvirt-client

Expand Down
2 changes: 1 addition & 1 deletion crates/bcvk-qemu/src/qemu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ pub enum BootMode {
/// Direct kernel boot (fast, testing-focused).
/// Also used for UKI boot after extracting kernel/initramfs from UKI PE sections.
///
/// Note: For UKI images, we extract kernel/initramfs using objcopy rather than
/// Note: For UKI images, we extract kernel/initramfs from PE sections rather than
/// booting the UKI directly via OVMF. This allows us to append bcvk units to
/// the initramfs for /etc overlay and /var setup. The tradeoff is that this
/// breaks the UKI signature chain, so Secure Boot is not supported for
Expand Down
2 changes: 1 addition & 1 deletion crates/integration-tests/src/tests/run_ephemeral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ integration_test!(test_run_ephemeral_instancetype_invalid);
/// Test that ephemeral VMs can boot from UKI-only images (no separate vmlinuz/initramfs)
///
/// This tests compatibility with bootc images that only ship a Unified Kernel Image,
/// verifying that bcvk can extract kernel/initramfs from the UKI using objcopy.
/// verifying that bcvk can extract kernel/initramfs from the UKI.
fn test_run_ephemeral_uki_only() -> TestResult {
let sh = shell()?;
let base_image = get_test_image();
Expand Down
1 change: 1 addition & 0 deletions crates/kit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ bcvk-qemu = { path = "../bcvk-qemu" }
cap-std-ext = { workspace = true }
bootc-mount = { package = "bootc-internal-mount", version = "1.16.14" }
bootc-utils = { package = "bootc-internal-utils", version = "1.16.14" }
composefs-boot = { version = "0.9.4", default-features = false }
rustix = { version = "1", features = ["thread", "net", "fs", "pipe", "system", "process", "mount"] }
vsock = "0.5"
nix = { version = "0.31", features = ["socket"] }
Expand Down
51 changes: 24 additions & 27 deletions crates/kit/src/run_ephemeral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1428,40 +1428,37 @@ pub(crate) async fn run_impl(opts: RunEphemeralOpts) -> Result<()> {

match kernel_info.kind {
crate::kernel::KernelKind::Uki => {
require_binary("objcopy")?;
debug!(
"Extracting kernel and initramfs from UKI: {:?}",
kernel_info.kernel_path
);
for (section, output) in [(".linux", kernel_mount), (".initrd", initramfs_mount)] {
Command::new("objcopy")
.args([
"--dump-section",
&format!("{section}={output}"),
kernel_info.kernel_path.as_str(),
])
.run_capture_stderr()
.map_err(|e| eyre!("Failed to extract {section} from UKI: {e}"))?;
let mut uki = File::open(&kernel_info.kernel_path).context("opening UKI")?;
for (section, target) in [(".linux", kernel_mount), (".initrd", initramfs_mount)] {
// The buffered parser starts at the current position in the image.
uki.rewind().context("rewinding UKI")?;
let contents = composefs_boot::uki::get_section_buffered(&mut uki, section)
.context(format!("extracting {section} from UKI"))?;
fs::write(target, contents).context(format!("writing {section} from UKI"))?;
debug!("Extracted {section} from UKI to {target}");
}
}
crate::kernel::KernelKind::AndroidBoot => {
require_binary("unpack_bootimg")?;
let unpacked = "/run/qemu/aboot-unpacked";
fs::create_dir_all(unpacked)?;
Command::new("unpack_bootimg")
.args([
"--boot_img",
kernel_info.kernel_path.as_str(),
"--out",
unpacked,
])
.stdout(Stdio::null())
.run_capture_stderr()
.map_err(|e| eyre!("Failed to unpack Android boot image: {e}"))?;
fs::rename(format!("{unpacked}/kernel"), kernel_mount)
.context("Getting kernel from Android boot image")?;
fs::rename(format!("{unpacked}/ramdisk"), initramfs_mount)
.context("Getting ramdisk from Android boot image")?;
use composefs_boot::android_boot::{AndroidBootImage, Component};

let mut image =
File::open(&kernel_info.kernel_path).context("opening Android boot image")?;
let header =
AndroidBootImage::parse(&mut image).context("parsing Android boot image")?;
for (component, name, target) in [
(Component::Kernel, "kernel", kernel_mount),
(Component::Ramdisk, "ramdisk", initramfs_mount),
] {
let contents = header
.component(&mut image, component)
.with_context(|| format!("extracting {name} from Android boot image"))?;
fs::write(target, contents)
.with_context(|| format!("writing {name} from Android boot image"))?;
}
}
crate::kernel::KernelKind::Traditional => {
let source_initramfs_path = kernel_info
Expand Down
2 changes: 0 additions & 2 deletions docs/src/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ For running bcvk:
- virtiofsd
- Podman
- openssh-clients (for libvirt SSH operations)
- binutils (for extracting UKIs, including ukiboot payloads)
- android-tools (for extracting Android boot images)
- kernel-tools (for initramfs bootconfig and ARM64 zstd EFI zboot kernels)

Optional:
Expand Down
2 changes: 1 addition & 1 deletion docs/todo/ephemeral-uefi.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Tracking issue: https://github.com/bootc-dev/bcvk/issues/161

Ephemeral VMs currently use direct kernel boot via QEMU's `-kernel` and
`-initrd` options. For UKI-only images, we extract the kernel and initramfs
from the UKI using `objcopy --dump-section`.
from the UKI using the `composefs-boot` UKI parser.

### Where UKIs Live in bootc Images

Expand Down
Loading