1
1
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
+ } ;
3
5
4
6
use anyhow:: { bail, Result } ;
5
7
@@ -207,41 +209,88 @@ impl<ObjectID: FsVerityHashValue> Type1Entry<ObjectID> {
207
209
}
208
210
}
209
211
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
+
210
222
#[ derive( Debug ) ]
211
223
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
214
227
pub file : RegularFile < ObjectID > ,
228
+ pub pe_type : PEType ,
215
229
}
216
230
217
231
impl < ObjectID : FsVerityHashValue > Type2Entry < ObjectID > {
218
232
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 ( ( ) )
220
286
}
221
287
222
288
pub fn load_all ( root : & Directory < ObjectID > ) -> Result < Vec < Self > > {
223
289
let mut entries = vec ! [ ] ;
224
290
225
291
match root. get_directory ( "/boot/EFI/Linux" . as_ref ( ) ) {
226
292
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 ( ) ) ?
245
294
}
246
295
Err ( ImageError :: NotFound ( ..) ) => { }
247
296
Err ( other) => Err ( other) ?,
@@ -254,11 +303,60 @@ impl<ObjectID: FsVerityHashValue> Type2Entry<ObjectID> {
254
303
#[ derive( Debug ) ]
255
304
pub struct UsrLibModulesUki < ObjectID : FsVerityHashValue > {
256
305
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 ,
259
309
}
260
310
261
311
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
+
262
360
pub fn load_all ( root : & Directory < ObjectID > ) -> Result < Vec < Self > > {
263
361
let mut entries = vec ! [ ] ;
264
362
@@ -269,25 +367,7 @@ impl<ObjectID: FsVerityHashValue> UsrLibModulesUki<ObjectID> {
269
367
continue ;
270
368
} ;
271
369
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) ?;
291
371
}
292
372
}
293
373
Err ( ImageError :: NotFound ( ..) ) => { }
0 commit comments