Skip to content

Commit 9b3437e

Browse files
cfs/uki: Use buffered readers
Use buffered readers for reading UKI sections instead of loading the entire thing in memory Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
1 parent f4e9a6a commit 9b3437e

3 files changed

Lines changed: 35 additions & 29 deletions

File tree

crates/lib/src/bootc_composefs/boot.rs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@
6262
//! 2. **Secondary**: Currently booted deployment (rollback option)
6363
6464
use std::fs::create_dir_all;
65-
use std::io::Read;
66-
use std::io::Write;
65+
use std::io::{Read, Seek, SeekFrom, Write};
6766
use std::path::Path;
6867
use std::sync::Arc;
6968

@@ -347,12 +346,10 @@ fn compute_boot_digest_type1(dir: &Dir) -> Result<String> {
347346
/// * entry - BootEntry containing VMlinuz and Initrd
348347
/// * repo - The composefs repository
349348
#[context("Computing boot digest")]
350-
pub(crate) fn compute_boot_digest_uki(uki: &[u8]) -> Result<String> {
351-
let vmlinuz =
352-
uki::get_section(uki, ".linux").ok_or_else(|| anyhow::anyhow!(".linux not present"))??;
353-
354-
let initramfs = uki::get_section(uki, ".initrd")
355-
.ok_or_else(|| anyhow::anyhow!(".initrd not present"))??;
349+
pub(crate) fn compute_boot_digest_uki<R: Read + Seek>(uki: &mut R) -> Result<String> {
350+
let vmlinuz = uki::get_section_buffered(uki, ".linux").context(".linux not present")?;
351+
uki.seek(SeekFrom::Start(0)).context("Moving seek to 0")?;
352+
let initramfs = uki::get_section_buffered(uki, ".initrd").context(".initrd not present")?;
356353

357354
let mut hasher = openssl::hash::Hasher::new(openssl::hash::MessageDigest::sha256())
358355
.context("Creating hasher")?;
@@ -796,17 +793,23 @@ fn write_pe_to_esp(
796793
missing_fsverity_allowed: bool,
797794
mounted_efi: impl AsRef<Path>,
798795
) -> Result<Option<UKIInfo>> {
799-
let efi_bin = read_file(file, &repo).context("Reading .efi binary")?;
796+
let mut uki_reader = match file {
797+
RegularFile::Inline(..) => {
798+
// UKI/Addons would always be large enough to be an external object
799+
anyhow::bail!("File too small to be UKI/Addon")
800+
}
801+
RegularFile::External(id, ..) => std::fs::File::from(repo.open_object(id)?),
802+
};
800803

801804
let mut boot_label: Option<UKIInfo> = None;
802805

803806
// UKI Extension might not even have a cmdline
804807
// TODO: UKI Addon might also have a composefs= cmdline?
805808
if matches!(pe_type, PEType::Uki) {
806-
let cmdline = uki::get_cmdline(&efi_bin).context("Getting UKI cmdline")?;
809+
let cmdline = uki::get_cmdline_buffered(&mut uki_reader).context("Getting UKI cmdline")?;
807810

808811
let (composefs_cmdline, missing_verity_allowed_cmdline) =
809-
get_cmdline_composefs::<Sha512HashValue>(cmdline).context("Parsing composefs=")?;
812+
get_cmdline_composefs::<Sha512HashValue>(&cmdline).context("Parsing composefs=")?;
810813

811814
// If the UKI cmdline does not match what the user has passed as cmdline option
812815
// NOTE: This will only be checked for new installs and now upgrades/switches
@@ -830,14 +833,18 @@ fn write_pe_to_esp(
830833
);
831834
}
832835

833-
let osrel = uki::get_text_section(&efi_bin, ".osrel")?;
836+
uki_reader.seek(SeekFrom::Start(0))?;
837+
let osrel = uki::get_text_section_buffered(&mut uki_reader, ".osrel")?;
834838

835-
let parsed_osrel = OsReleaseInfo::parse(osrel);
839+
let parsed_osrel = OsReleaseInfo::parse(&osrel);
836840

837-
let boot_digest = compute_boot_digest_uki(&efi_bin)?;
841+
uki_reader.seek(SeekFrom::Start(0))?;
842+
let boot_digest = compute_boot_digest_uki(&mut uki_reader)?;
838843

844+
uki_reader.seek(SeekFrom::Start(0))?;
839845
boot_label = Some(UKIInfo {
840-
boot_label: uki::get_boot_label(&efi_bin).context("Getting UKI boot label")?,
846+
boot_label: uki::get_boot_label_buffered(&mut uki_reader)
847+
.context("Getting UKI boot label")?,
841848
version: parsed_osrel.get_version(),
842849
os_id: parsed_osrel.get_value(&["ID"]),
843850
boot_digest,
@@ -883,8 +890,9 @@ fn write_pe_to_esp(
883890
.as_str(),
884891
};
885892

893+
uki_reader.seek(SeekFrom::Start(0))?;
886894
pe_dir
887-
.atomic_write(pe_name, efi_bin)
895+
.atomic_replace_with(pe_name, |writer| std::io::copy(&mut uki_reader, writer))
888896
.context("Writing UKI")?;
889897

890898
rustix::fs::fsync(

crates/lib/src/bootc_composefs/utils.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use bootc_kernel_cmdline::utf8::Cmdline;
1010
use composefs_ctl::composefs_boot;
1111
use fn_error_context::context;
1212

13-
fn get_uki(storage: &Storage, deployment_verity: &str) -> Result<Vec<u8>> {
13+
fn get_uki(storage: &Storage, deployment_verity: &str) -> Result<cap_std_ext::cap_std::fs::File> {
1414
let uki_dir = storage.require_esp()?.fd.open_dir(BOOTC_UKI_DIR)?;
1515

1616
let req_fname = get_uki_name(deployment_verity);
@@ -24,7 +24,7 @@ fn get_uki(storage: &Storage, deployment_verity: &str) -> Result<Vec<u8>> {
2424
continue;
2525
}
2626

27-
return Ok(uki_dir.read(filename)?);
27+
return Ok(uki_dir.open(filename)?);
2828
}
2929

3030
anyhow::bail!("UKI for deployment {deployment_verity} not found")
@@ -35,8 +35,8 @@ pub(crate) fn compute_store_boot_digest_for_uki(
3535
storage: &Storage,
3636
deployment_verity: &str,
3737
) -> Result<String> {
38-
let uki = get_uki(storage, deployment_verity)?;
39-
let digest = compute_boot_digest_uki(&uki)?;
38+
let mut uki = get_uki(storage, deployment_verity)?;
39+
let digest = compute_boot_digest_uki(&mut uki)?;
4040

4141
update_boot_digest_in_origin(storage, &deployment_verity, &digest)?;
4242
return Ok(digest);
@@ -47,8 +47,8 @@ pub(crate) fn get_uki_cmdline(
4747
storage: &Storage,
4848
deployment_verity: &str,
4949
) -> Result<Cmdline<'static>> {
50-
let uki = get_uki(storage, deployment_verity)?;
51-
let cmdline = composefs_boot::uki::get_cmdline(&uki)?;
50+
let mut uki = get_uki(storage, deployment_verity)?;
51+
let cmdline = composefs_boot::uki::get_cmdline_buffered(&mut uki)?;
5252

5353
return Ok(Cmdline::from(cmdline.to_owned()));
5454
}

crates/lib/src/kernel.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,18 @@ pub(crate) fn find_kernel(root: &Dir) -> Result<Option<KernelInternal>> {
7575
if let Some(uki_path) = find_uki_path(root)? {
7676
let version = uki_path.file_stem().unwrap_or(uki_path.as_str()).to_owned();
7777

78-
let uki = root.read(&uki_path).context("Reading UKI")?;
78+
let mut uki = root.open(&uki_path).context("Opening UKI")?;
7979

8080
// Best effort to check for composefs=?verity in the UKI cmdline
81-
let cmdline = composefs_boot::uki::get_section(&uki, ".cmdline");
81+
let cmdline = composefs_boot::uki::get_section_buffered(&mut uki, ".cmdline");
8282

8383
let cmdline = match cmdline {
84-
Some(Ok(cmdline)) => {
85-
let cmdline_str = std::str::from_utf8(cmdline)?;
84+
Ok(cmdline) => {
85+
let cmdline_str = std::str::from_utf8(&cmdline)?;
8686
Some(Cmdline::from(cmdline_str.to_owned()))
8787
}
8888

89-
Some(Err(uki_error)) => match uki_error {
89+
Err(uki_error) => match uki_error {
9090
composefs_boot::uki::UkiError::MissingSection(_) => {
9191
// TODO(Johan-Liebert1): Check this when we have full UKI Addons support
9292
// The cmdline might be in an addon, so don't allow missing verity
@@ -95,8 +95,6 @@ pub(crate) fn find_kernel(root: &Dir) -> Result<Option<KernelInternal>> {
9595

9696
e => anyhow::bail!("Failed to read UKI cmdline: {e:?}"),
9797
},
98-
99-
None => None,
10098
};
10199

102100
return Ok(Some(KernelInternal {

0 commit comments

Comments
 (0)