Skip to content

Commit fc18730

Browse files
boot: Collect UKI addons
While collecting UKI from /boot/EFI/Linux or /usr/lib/modules we now also collect UKI addons from any directory that ends with `.efi.extra.d` Signed-off-by: Johan-Liebert1 <[email protected]>
1 parent ce28ee8 commit fc18730

File tree

2 files changed

+124
-44
lines changed

2 files changed

+124
-44
lines changed

crates/composefs-boot/src/bootloader.rs

Lines changed: 123 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use core::ops::Range;
2-
use std::{collections::HashMap, ffi::OsStr, os::unix::ffi::OsStrExt, str::from_utf8};
2+
use std::{
3+
collections::HashMap, ffi::OsStr, os::unix::ffi::OsStrExt, path::PathBuf, str::from_utf8,
4+
};
35

46
use anyhow::{bail, Result};
57

@@ -207,41 +209,88 @@ impl<ObjectID: FsVerityHashValue> Type1Entry<ObjectID> {
207209
}
208210
}
209211

212+
pub const EFI_EXT: &str = ".efi";
213+
pub const EFI_ADDON_DIR_EXT: &str = ".efi.extra.d";
214+
pub const EFI_ADDON_FILE_EXT: &str = ".addon.efi";
215+
216+
#[derive(Debug)]
217+
pub enum PEType {
218+
Uki,
219+
UkiAddon,
220+
}
221+
210222
#[derive(Debug)]
211223
pub struct Type2Entry<ObjectID: FsVerityHashValue> {
212-
// This is the basename of the UKI .efi file
213-
pub filename: Box<OsStr>,
224+
// This is the path (relative to /boot/EFI/Linux) of the file
225+
pub file_path: Box<PathBuf>,
226+
// The Portable Executable binary
214227
pub file: RegularFile<ObjectID>,
228+
pub pe_type: PEType,
215229
}
216230

217231
impl<ObjectID: FsVerityHashValue> Type2Entry<ObjectID> {
218232
pub fn rename(&mut self, name: &str) {
219-
self.filename = Box::from(format!("{name}.efi").as_ref());
233+
let new_name = format!("{name}.efi");
234+
235+
if let Some(parent) = self.file_path.parent() {
236+
self.file_path = Box::new(parent.join(new_name));
237+
} else {
238+
self.file_path = Box::new(new_name.into());
239+
}
240+
}
241+
242+
fn recurse_dir(
243+
dir: &Directory<ObjectID>,
244+
entries: &mut Vec<Self>,
245+
path: &mut PathBuf,
246+
) -> Result<()> {
247+
for (filename, inode) in dir.entries() {
248+
path.push(filename);
249+
250+
// We also want to collect all UKI extensions
251+
if let Inode::Directory(dir) = inode {
252+
if !filename.as_bytes().ends_with(EFI_ADDON_DIR_EXT.as_bytes()) {
253+
continue;
254+
}
255+
256+
Type2Entry::recurse_dir(dir, entries, path)?;
257+
return Ok(());
258+
}
259+
260+
if !filename.as_bytes().ends_with(EFI_EXT.as_bytes()) {
261+
continue;
262+
}
263+
264+
let Inode::Leaf(leaf) = inode else {
265+
bail!("/boot/EFI/Linux/{filename:?} is a directory");
266+
};
267+
268+
let LeafContent::Regular(file) = &leaf.content else {
269+
bail!("/boot/EFI/Linux/{filename:?} is not a regular file");
270+
};
271+
272+
entries.push(Self {
273+
file_path: Box::from(path.clone()),
274+
file: file.clone(),
275+
pe_type: if path.components().count() == 1 {
276+
PEType::Uki
277+
} else {
278+
PEType::UkiAddon
279+
},
280+
});
281+
282+
path.pop();
283+
}
284+
285+
Ok(())
220286
}
221287

222288
pub fn load_all(root: &Directory<ObjectID>) -> Result<Vec<Self>> {
223289
let mut entries = vec![];
224290

225291
match root.get_directory("/boot/EFI/Linux".as_ref()) {
226292
Ok(entries_dir) => {
227-
for (filename, inode) in entries_dir.entries() {
228-
if !filename.as_bytes().ends_with(b".efi") {
229-
continue;
230-
}
231-
232-
let Inode::Leaf(leaf) = inode else {
233-
bail!("/boot/EFI/Linux/{filename:?} is a directory");
234-
};
235-
236-
let LeafContent::Regular(file) = &leaf.content else {
237-
bail!("/boot/EFI/Linux/{filename:?} is not a regular file");
238-
};
239-
240-
entries.push(Self {
241-
filename: Box::from(filename),
242-
file: file.clone(),
243-
})
244-
}
293+
Type2Entry::recurse_dir(entries_dir, &mut entries, &mut PathBuf::new())?
245294
}
246295
Err(ImageError::NotFound(..)) => {}
247296
Err(other) => Err(other)?,
@@ -254,11 +303,60 @@ impl<ObjectID: FsVerityHashValue> Type2Entry<ObjectID> {
254303
#[derive(Debug)]
255304
pub struct UsrLibModulesUki<ObjectID: FsVerityHashValue> {
256305
pub kver: Box<OsStr>,
257-
pub filename: Box<OsStr>,
258-
pub uki: RegularFile<ObjectID>,
306+
pub file_path: PathBuf,
307+
pub file: RegularFile<ObjectID>,
308+
pub pe_type: PEType,
259309
}
260310

261311
impl<ObjectID: FsVerityHashValue> UsrLibModulesUki<ObjectID> {
312+
fn recurse_dir(
313+
dir: &Directory<ObjectID>,
314+
entries: &mut Vec<Self>,
315+
path: &mut PathBuf,
316+
kver: &OsStr,
317+
) -> Result<()> {
318+
for (filename, inode) in dir.entries() {
319+
path.push(filename);
320+
321+
// Collect all UKI extensions
322+
if let Inode::Directory(dir) = inode {
323+
if !filename.as_bytes().ends_with(EFI_ADDON_DIR_EXT.as_bytes()) {
324+
continue;
325+
}
326+
327+
UsrLibModulesUki::recurse_dir(dir, entries, path, kver)?;
328+
return Ok(());
329+
}
330+
331+
if !filename.as_bytes().ends_with(EFI_EXT.as_bytes()) {
332+
continue;
333+
}
334+
335+
let Inode::Leaf(leaf) = inode else {
336+
bail!("/usr/lib/modules/{filename:?} is a directory");
337+
};
338+
339+
let LeafContent::Regular(file) = &leaf.content else {
340+
bail!("/usr/lib/modules/{filename:?} is not a regular file");
341+
};
342+
343+
entries.push(Self {
344+
kver: Box::from(kver),
345+
file_path: path.clone(),
346+
file: file.clone(),
347+
pe_type: if path.components().count() == 0 {
348+
PEType::Uki
349+
} else {
350+
PEType::UkiAddon
351+
},
352+
});
353+
354+
path.pop();
355+
}
356+
357+
Ok(())
358+
}
359+
262360
pub fn load_all(root: &Directory<ObjectID>) -> Result<Vec<Self>> {
263361
let mut entries = vec![];
264362

@@ -269,25 +367,7 @@ impl<ObjectID: FsVerityHashValue> UsrLibModulesUki<ObjectID> {
269367
continue;
270368
};
271369

272-
for (filename, inode) in dir.entries() {
273-
if !filename.as_bytes().ends_with(b".efi") {
274-
continue;
275-
}
276-
277-
let Inode::Leaf(leaf) = inode else {
278-
bail!("/boot/EFI/Linux/{filename:?} is a directory");
279-
};
280-
281-
let LeafContent::Regular(file) = &leaf.content else {
282-
bail!("/boot/EFI/Linux/{filename:?} is not a regular file");
283-
};
284-
285-
entries.push(Self {
286-
kver: Box::from(kver),
287-
filename: Box::from(filename),
288-
uki: file.clone(),
289-
})
290-
}
370+
UsrLibModulesUki::recurse_dir(dir, &mut entries, &mut PathBuf::new(), kver)?;
291371
}
292372
}
293373
Err(ImageError::NotFound(..)) => {}

crates/composefs-boot/src/write_boot.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub fn write_t2_simple<ObjectID: FsVerityHashValue>(
5858
) -> Result<()> {
5959
let efi_linux = bootdir.join("EFI/Linux");
6060
create_dir_all(&efi_linux)?;
61-
let filename = efi_linux.join(t2.filename.as_ref());
61+
let filename = efi_linux.join(t2.file_path.as_ref());
6262
let content = composefs::fs::read_file(&t2.file, repo)?;
6363
let (composefs, _) = get_cmdline_composefs::<ObjectID>(uki::get_cmdline(&content)?)?;
6464

0 commit comments

Comments
 (0)