Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions docs/elfio_files/bad_align_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ int main( void )
// Create a loadable segment
segment* text_seg = writer.segments.add();
text_seg->set_type( PT_LOAD );
text_seg->set_virtual_address( 0x400 );
text_seg->set_physical_address( 0x400 );
text_seg->set_virtual_address( 0x200000 );
text_seg->set_physical_address( 0x200000 );
text_seg->set_flags( PF_X | PF_R );
text_seg->set_align( 0x100 );
text_seg->set_align( 0x200000 );

// Add code section into program segment
text_seg->add_section_index( text_sec->get_index(),
Expand All @@ -80,10 +80,10 @@ int main( void )
// Create a read/write segment
segment* data_seg = writer.segments.add();
data_seg->set_type( PT_NOTE );
data_seg->set_virtual_address( 0x8888048020 );
data_seg->set_physical_address( 0x8888048020 );
data_seg->set_virtual_address( 0x8888400000 );
data_seg->set_physical_address( 0x888400000 );
data_seg->set_flags( PF_W | PF_R );
data_seg->set_align( 13 );
data_seg->set_align( 0x200000 );

// Add code section into program segment
data_seg->add_section_index( data_sec->get_index(),
Expand All @@ -103,7 +103,7 @@ int main( void )
// In this example, the code starts at the first address of the
// 'text_seg' segment. Therefore, the start address is set
// to be equal to the segment location
writer.set_entry( 0x400 );
writer.set_entry( 0x200000 );

// Create ELF file
writer.save( "test_bad_align.bin" );
Expand Down
14 changes: 7 additions & 7 deletions docs/elfio_files/basic_elf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ int main( void )
// Create a loadable segment
segment* text_seg = writer.segments.add();
text_seg->set_type( PT_LOAD );
text_seg->set_virtual_address( 0x400 );
text_seg->set_physical_address( 0x0 );
text_seg->set_virtual_address( 0x200000 );
text_seg->set_physical_address( 0x200000 );
text_seg->set_flags( PF_X | PF_R );
text_seg->set_align( 0x1 );
text_seg->set_align( 0x200000 );

// Add code section into program segment
text_seg->add_section_index( text_sec->get_index(),
Expand All @@ -80,10 +80,10 @@ int main( void )
// Create a read/write segment
segment* data_seg = writer.segments.add();
data_seg->set_type( PT_LOAD );
data_seg->set_virtual_address( 0x0420 );
data_seg->set_physical_address( 0x0420 );
data_seg->set_virtual_address( 0x400000 );
data_seg->set_physical_address( 0x400000 );
data_seg->set_flags( PF_W | PF_R );
data_seg->set_align( 0x10 );
data_seg->set_align( 0x200000 );

// Add code section into program segment
data_seg->add_section_index( data_sec->get_index(),
Expand All @@ -103,7 +103,7 @@ int main( void )
// In this example, the code starts at the first address of the
// 'text_seg' segment. Therefore, the start address is set
// to be equal to the segment location
writer.set_entry( 0x400 );
writer.set_entry( 0x200000 );

// Create ELF file
writer.save( "test_elf.bin" );
Expand Down
45 changes: 38 additions & 7 deletions src/loader/elf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ impl fmt::Display for PvhBootCapability {
/// Raw ELF (a.k.a. vmlinux) kernel image support.
pub struct Elf;

// x86-64 kernel must be aligned to 2MB.
const KERNEL_SEGMENT_ALIGN: u64 = 0x200000; // 2 MiB

impl Elf {
/// Verifies that magic numbers are present in the Elf header.
fn validate_header(ehdr: &elf::Elf64_Ehdr) -> std::result::Result<(), Error> {
Expand Down Expand Up @@ -224,12 +227,18 @@ impl KernelLoader for Elf {

let mut loader_result = KernelLoaderResult {
kernel_load: match kernel_offset {
Some(k_offset) => GuestAddress(
k_offset
Some(k_offset) => {
let load_addr = k_offset
.raw_value()
.checked_add(ehdr.e_entry)
.ok_or(Error::Overflow)?,
),
.ok_or(Error::Overflow)?;
// Ensure that kernel_offset is aligned to 2M, otherwise, the kernel may hang during
// booting. Refer to the check in __startup_64() in the Linux kernel source code.
if k_offset.raw_value() & (KERNEL_SEGMENT_ALIGN - 1) != 0 {
return Err(Error::Align.into());
}
GuestAddress(load_addr)
},
None => GuestAddress(ehdr.e_entry),
},
..Default::default()
Expand Down Expand Up @@ -271,6 +280,12 @@ impl KernelLoader for Elf {
.seek(SeekFrom::Start(phdr.p_offset))
.map_err(|_| Error::SeekKernelStart)?;

// Verify alignment of the LOAD segment.
// See commit c55b8550fa57ba4f5e507be406ff9fc2845713e8 in Linux kernel tree.
if phdr.p_align & (KERNEL_SEGMENT_ALIGN - 1) != 0 {
return Err(Error::Align.into());
}

// if the vmm does not specify where the kernel should be loaded, just
// load it to the physical address p_paddr for each segment.
let mem_offset = match kernel_offset {
Expand Down Expand Up @@ -479,10 +494,10 @@ mod tests {
Some(highmem_start_address),
)
.unwrap();
assert_eq!(loader_result.kernel_load.raw_value(), 0x200400);
assert_eq!(loader_result.kernel_load.raw_value(), 0x400000);

loader_result = Elf::load(&gm, Some(kernel_addr), &mut Cursor::new(&image), None).unwrap();
assert_eq!(loader_result.kernel_load.raw_value(), 0x200400);
assert_eq!(loader_result.kernel_load.raw_value(), 0x400000);

loader_result = Elf::load(
&gm,
Expand All @@ -491,7 +506,7 @@ mod tests {
Some(highmem_start_address),
)
.unwrap();
assert_eq!(loader_result.kernel_load.raw_value(), 0x400);
assert_eq!(loader_result.kernel_load.raw_value(), 0x200000);

highmem_start_address = GuestAddress(0xa00000);
assert_eq!(
Expand Down Expand Up @@ -632,4 +647,20 @@ mod tests {
.err()
);
}

#[test]
fn test_unaligned_loadaddr() {
let gm = create_guest_mem();
let image = make_elf_bin();
assert_eq!(
Some(KernelLoaderError::Elf(Error::Align)),
Elf::load(
&gm,
Some(GuestAddress(0x1000)),
&mut Cursor::new(&image),
None
)
.err()
);
}
}
Binary file modified src/loader/elf/test_bad_align.bin
Binary file not shown.
Binary file modified src/loader/elf/test_elf.bin
Binary file not shown.