11use 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
46use 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 ) ]
211223pub 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 : PathBuf ,
226+ // The Portable Executable binary
214227 pub file : RegularFile < ObjectID > ,
228+ pub pe_type : PEType ,
215229}
216230
217231impl < 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 = parent. join ( new_name) ;
237+ } else {
238+ self . file_path = 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 : 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 ) ]
255304pub 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
261311impl < 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 ( ..) ) => { }
0 commit comments