15
15
use std:: fmt;
16
16
use std:: io:: { Read , Seek , SeekFrom } ;
17
17
use std:: mem;
18
+ use std:: result;
18
19
19
20
use vm_memory:: { Address , ByteValued , Bytes , GuestAddress , GuestMemory , GuestUsize } ;
20
21
@@ -29,9 +30,11 @@ unsafe impl ByteValued for elf::Elf64_Phdr {}
29
30
#[ derive( Debug , PartialEq ) ]
30
31
/// Elf kernel loader errors.
31
32
pub enum Error {
33
+ /// Invalid alignment.
34
+ Align ,
32
35
/// Loaded big endian binary on a little endian platform.
33
36
BigEndianElfOnLittle ,
34
- /// Invalid ELF magic number
37
+ /// Invalid ELF magic number.
35
38
InvalidElfMagicNumber ,
36
39
/// Invalid program header size.
37
40
InvalidProgramHeaderSize ,
@@ -64,6 +67,7 @@ pub enum Error {
64
67
impl fmt:: Display for Error {
65
68
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
66
69
let desc = match self {
70
+ Error :: Align => "Invalid alignment" ,
67
71
Error :: BigEndianElfOnLittle => {
68
72
"Trying to load big-endian binary on little-endian machine"
69
73
}
@@ -332,8 +336,8 @@ where
332
336
333
337
// Skip the note header plus the size of its fields (with alignment).
334
338
read_size += nhdr_sz
335
- + align_up ( u64:: from ( nhdr. n_namesz ) , n_align)
336
- + align_up ( u64:: from ( nhdr. n_descsz ) , n_align) ;
339
+ + align_up ( u64:: from ( nhdr. n_namesz ) , n_align) ?
340
+ + align_up ( u64:: from ( nhdr. n_descsz ) , n_align) ? ;
337
341
338
342
kernel_image
339
343
. seek ( SeekFrom :: Start ( phdr. p_offset + read_size as u64 ) )
@@ -350,7 +354,7 @@ where
350
354
// just skip the name field contents.
351
355
kernel_image
352
356
. seek ( SeekFrom :: Current (
353
- align_up ( u64:: from ( nhdr. n_namesz ) , n_align) as i64 - PVH_NOTE_STR_SZ as i64 ,
357
+ align_up ( u64:: from ( nhdr. n_namesz ) , n_align) ? as i64 - PVH_NOTE_STR_SZ as i64 ,
354
358
) )
355
359
. map_err ( |_| Error :: SeekNoteHeader ) ?;
356
360
@@ -372,18 +376,20 @@ where
372
376
) ) )
373
377
}
374
378
375
- /// Align address upwards. Taken from x86_64 crate:
376
- /// https://docs.rs/x86_64/latest/x86_64/fn.align_up.html
379
+ /// Align address upwards. Adapted from x86_64 crate:
380
+ /// https://docs.rs/x86_64/latest/x86_64/addr/ fn.align_up.html
377
381
///
378
- /// Returns the smallest x with alignment `align` so that x >= addr. The alignment must be
379
- /// a power of 2.
380
- fn align_up ( addr : u64 , align : u64 ) -> usize {
381
- assert ! ( align. is_power_of_two( ) , "`align` must be a power of two" ) ;
382
+ /// Returns the smallest x with alignment `align` so that x >= addr if the alignment is a power of
383
+ /// 2, or an error otherwise.
384
+ fn align_up ( addr : u64 , align : u64 ) -> result:: Result < usize , Error > {
385
+ if !align. is_power_of_two ( ) {
386
+ return Err ( Error :: Align ) ;
387
+ }
382
388
let align_mask = align - 1 ;
383
389
if addr & align_mask == 0 {
384
- addr as usize // already aligned
390
+ Ok ( addr as usize ) // already aligned
385
391
} else {
386
- ( ( addr | align_mask) + 1 ) as usize
392
+ Ok ( ( ( addr | align_mask) + 1 ) as usize )
387
393
}
388
394
}
389
395
@@ -417,6 +423,10 @@ mod tests {
417
423
include_bytes ! ( "test_badnote.bin" ) . to_vec ( )
418
424
}
419
425
426
+ fn make_bad_align ( ) -> Vec < u8 > {
427
+ include_bytes ! ( "test_align.bin" ) . to_vec ( )
428
+ }
429
+
420
430
#[ test]
421
431
fn test_load_elf ( ) {
422
432
let gm = create_guest_mem ( ) ;
@@ -539,4 +549,14 @@ mod tests {
539
549
Elf :: load( & gm, None , & mut Cursor :: new( & badnote_image) , None ) . err( )
540
550
) ;
541
551
}
552
+
553
+ #[ test]
554
+ fn test_bad_align ( ) {
555
+ let gm = GuestMemoryMmap :: from_ranges ( & [ ( GuestAddress ( 0x0 ) , ( 0x10_000_000usize ) ) ] ) . unwrap ( ) ;
556
+ let bad_align_image = make_bad_align ( ) ;
557
+ assert_eq ! (
558
+ Some ( KernelLoaderError :: Elf ( Error :: Align ) ) ,
559
+ Elf :: load( & gm, None , & mut Cursor :: new( & bad_align_image) , None ) . err( )
560
+ ) ;
561
+ }
542
562
}
0 commit comments