Skip to main content

linux_loader/loader/elf/
mod.rs

1// Copyright © 2020, Oracle and/or its affiliates.
2// Copyright (c) 2019 Intel Corporation. All rights reserved.
3// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4//
5// Copyright 2017 The Chromium OS Authors. All rights reserved.
6// Use of this source code is governed by a BSD-style license that can be
7// found in the LICENSE-BSD-3-Clause file.
8//
9// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
10
11//! Traits and structs for loading elf image kernels into guest memory.
12
13#![cfg(all(feature = "elf", any(target_arch = "x86", target_arch = "x86_64")))]
14
15use std::fmt;
16use std::io::{Read, Seek, SeekFrom};
17use std::mem;
18use std::result;
19
20use vm_memory::{
21    Address, ByteValued, Bytes, GuestAddress, GuestMemoryBackend, GuestUsize, ReadVolatile,
22};
23
24use crate::loader::{Error as KernelLoaderError, KernelLoader, KernelLoaderResult, Result};
25use crate::loader_gen::elf;
26pub use crate::loader_gen::start_info;
27
28// SAFETY: The layout of the structure is fixed and can be initialized by
29// reading its content from byte array.
30unsafe impl ByteValued for elf::Elf64_Ehdr {}
31
32// SAFETY: The layout of the structure is fixed and can be initialized by
33// reading its content from byte array.
34unsafe impl ByteValued for elf::Elf64_Nhdr {}
35
36// SAFETY: The layout of the structure is fixed and can be initialized by
37// reading its content from byte array.
38unsafe impl ByteValued for elf::Elf64_Phdr {}
39
40#[derive(Debug, PartialEq, Eq)]
41/// Elf kernel loader errors.
42pub enum Error {
43    /// Invalid alignment.
44    Align,
45    /// Loaded big endian binary on a little endian platform.
46    BigEndianElfOnLittle,
47    /// Invalid ELF magic number.
48    InvalidElfMagicNumber,
49    /// Invalid program header size.
50    InvalidProgramHeaderSize,
51    /// Invalid program header offset.
52    InvalidProgramHeaderOffset,
53    /// Invalid program header address.
54    InvalidProgramHeaderAddress,
55    /// Invalid entry address.
56    InvalidEntryAddress,
57    /// Overflow occurred during an arithmetic operation.
58    Overflow,
59    /// Unable to read ELF header.
60    ReadElfHeader,
61    /// Unable to read kernel image.
62    ReadKernelImage,
63    /// Unable to read program header.
64    ReadProgramHeader,
65    /// Unable to seek to kernel start.
66    SeekKernelStart,
67    /// Unable to seek to ELF start.
68    SeekElfStart,
69    /// Unable to seek to program header.
70    SeekProgramHeader,
71    /// Unable to seek to note header.
72    SeekNoteHeader,
73    /// Unable to read note header.
74    ReadNoteHeader,
75    /// Invalid PVH note.
76    InvalidPvhNote,
77}
78
79impl fmt::Display for Error {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        let desc = match self {
82            Error::Align => "Invalid alignment",
83            Error::BigEndianElfOnLittle => {
84                "Trying to load big-endian binary on little-endian machine"
85            }
86            Error::InvalidElfMagicNumber => "Invalid Elf magic number",
87            Error::InvalidProgramHeaderSize => "Invalid program header size",
88            Error::InvalidProgramHeaderOffset => "Invalid program header offset",
89            Error::InvalidProgramHeaderAddress => "Invalid Program Header Address",
90            Error::InvalidEntryAddress => "Invalid entry address",
91            Error::Overflow => "Overflow occurred during an arithmetic operation",
92            Error::ReadElfHeader => "Unable to read elf header",
93            Error::ReadKernelImage => "Unable to read kernel image",
94            Error::ReadProgramHeader => "Unable to read program header",
95            Error::SeekKernelStart => "Unable to seek to kernel start",
96            Error::SeekElfStart => "Unable to seek to elf start",
97            Error::SeekProgramHeader => "Unable to seek to program header",
98            Error::SeekNoteHeader => "Unable to seek to note header",
99            Error::ReadNoteHeader => "Unable to read note header",
100            Error::InvalidPvhNote => "Invalid PVH note header",
101        };
102
103        write!(f, "Kernel Loader: {}", desc)
104    }
105}
106
107impl std::error::Error for Error {}
108
109#[derive(Clone, Default, Copy, Debug, PartialEq, Eq)]
110/// Availability of PVH entry point in the kernel, which allows the VMM
111/// to use the PVH boot protocol to start guests.
112pub enum PvhBootCapability {
113    /// PVH entry point is present
114    PvhEntryPresent(GuestAddress),
115    /// PVH entry point is not present
116    PvhEntryNotPresent,
117    /// PVH entry point is ignored, even if available
118    #[default]
119    PvhEntryIgnored,
120}
121
122impl fmt::Display for PvhBootCapability {
123    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124        use self::PvhBootCapability::*;
125        match self {
126            PvhEntryPresent(pvh_entry_addr) => write!(
127                f,
128                "PVH entry point present at guest address: {:#x}",
129                pvh_entry_addr.raw_value()
130            ),
131            PvhEntryNotPresent => write!(f, "PVH entry point not present"),
132            PvhEntryIgnored => write!(f, "PVH entry point ignored"),
133        }
134    }
135}
136
137/// Raw ELF (a.k.a. vmlinux) kernel image support.
138pub struct Elf;
139
140impl Elf {
141    /// Verifies that magic numbers are present in the Elf header.
142    fn validate_header(ehdr: &elf::Elf64_Ehdr) -> std::result::Result<(), Error> {
143        // Sanity checks
144        if ehdr.e_ident[elf::EI_MAG0] != elf::ELFMAG0
145            || ehdr.e_ident[elf::EI_MAG1] != elf::ELFMAG1
146            || ehdr.e_ident[elf::EI_MAG2] != elf::ELFMAG2
147            || ehdr.e_ident[elf::EI_MAG3] != elf::ELFMAG3
148        {
149            return Err(Error::InvalidElfMagicNumber);
150        }
151        if ehdr.e_ident[elf::EI_DATA] != elf::ELFDATA2LSB {
152            return Err(Error::BigEndianElfOnLittle);
153        }
154        if ehdr.e_phentsize as usize != mem::size_of::<elf::Elf64_Phdr>() {
155            return Err(Error::InvalidProgramHeaderSize);
156        }
157        if (ehdr.e_phoff as usize) < mem::size_of::<elf::Elf64_Ehdr>() {
158            return Err(Error::InvalidProgramHeaderOffset);
159        }
160        Ok(())
161    }
162}
163
164impl KernelLoader for Elf {
165    /// Loads a kernel from a vmlinux elf image into guest memory.
166    ///
167    /// By default, the kernel is loaded into guest memory at offset `phdr.p_paddr` specified
168    /// by the elf image. When used, `kernel_offset` specifies a fixed offset from `phdr.p_paddr`
169    /// at which to load the kernel. If `kernel_offset` is requested, the `pvh_entry_addr` field
170    /// of the result will not be populated.
171    ///
172    /// # Arguments
173    ///
174    /// * `guest_mem`: [`GuestMemoryBackend`] to load the kernel in.
175    /// * `kernel_offset`: Offset to be added to default kernel load address in guest memory.
176    /// * `kernel_image` - Input vmlinux image.
177    /// * `highmem_start_address`: Address where high memory starts.
178    ///
179    /// # Examples
180    ///
181    /// ```rust
182    /// # extern crate vm_memory;
183    /// # use std::io::Cursor;
184    /// # use linux_loader::loader::*;
185    /// # use vm_memory::{Address, GuestAddress};
186    /// # type GuestMemoryMmap = vm_memory::GuestMemoryMmap<()>;
187    /// let mem_size: usize = 0x1000000;
188    /// let himem_start = GuestAddress(0x0);
189    /// let kernel_addr = GuestAddress(0x200000);
190    /// let gm = GuestMemoryMmap::from_ranges(&[(GuestAddress(0x0), mem_size)]).unwrap();
191    /// let mut kernel_image = vec![];
192    /// kernel_image.extend_from_slice(include_bytes!("test_elf.bin"));
193    /// elf::Elf::load(
194    ///     &gm,
195    ///     Some(kernel_addr),
196    ///     &mut Cursor::new(&kernel_image),
197    ///     Some(himem_start),
198    /// )
199    /// .unwrap();
200    /// ```
201    ///
202    /// [`GuestMemoryBackend`]: https://docs.rs/vm-memory/latest/vm_memory/guest_memory/trait.GuestMemoryBackend.html
203    fn load<F, M: GuestMemoryBackend>(
204        guest_mem: &M,
205        kernel_offset: Option<GuestAddress>,
206        kernel_image: &mut F,
207        highmem_start_address: Option<GuestAddress>,
208    ) -> Result<KernelLoaderResult>
209    where
210        F: Read + ReadVolatile + Seek,
211    {
212        kernel_image.rewind().map_err(|_| Error::SeekElfStart)?;
213
214        let mut ehdr = elf::Elf64_Ehdr::default();
215        kernel_image
216            .read_exact(ehdr.as_mut_slice())
217            .map_err(|_| Error::ReadElfHeader)?;
218
219        // Sanity checks.
220        Self::validate_header(&ehdr)?;
221        if let Some(addr) = highmem_start_address {
222            if (ehdr.e_entry) < addr.raw_value() {
223                return Err(Error::InvalidEntryAddress.into());
224            }
225        }
226
227        let mut loader_result = KernelLoaderResult {
228            kernel_load: match kernel_offset {
229                Some(k_offset) => GuestAddress(
230                    k_offset
231                        .raw_value()
232                        .checked_add(ehdr.e_entry)
233                        .ok_or(Error::Overflow)?,
234                ),
235                None => GuestAddress(ehdr.e_entry),
236            },
237            ..Default::default()
238        };
239
240        kernel_image
241            .seek(SeekFrom::Start(ehdr.e_phoff))
242            .map_err(|_| Error::SeekProgramHeader)?;
243
244        let mut phdrs: Vec<elf::Elf64_Phdr> = vec![];
245        for _ in 0usize..ehdr.e_phnum as usize {
246            let mut phdr = elf::Elf64_Phdr::default();
247            kernel_image
248                .read_exact(phdr.as_mut_slice())
249                .map_err(|_| Error::ReadProgramHeader)?;
250            phdrs.push(phdr);
251        }
252
253        // Read in each section pointed to by the program headers.
254        for phdr in phdrs {
255            if phdr.p_type != elf::PT_LOAD || phdr.p_filesz == 0 {
256                if phdr.p_type == elf::PT_NOTE {
257                    // The PVH boot protocol currently requires that the kernel is loaded at
258                    // the default kernel load address in guest memory (specified at kernel
259                    // build time by the value of CONFIG_PHYSICAL_START). Therefore, only
260                    // attempt to use PVH if an offset from the default load address has not
261                    // been requested using the kernel_offset parameter.
262                    if let Some(_offset) = kernel_offset {
263                        loader_result.pvh_boot_cap = PvhBootCapability::PvhEntryIgnored;
264                    } else {
265                        // If kernel_offset is not requested, check if PVH entry point is present
266                        loader_result.pvh_boot_cap = parse_elf_note(&phdr, kernel_image)?;
267                    }
268                }
269                continue;
270            }
271
272            kernel_image
273                .seek(SeekFrom::Start(phdr.p_offset))
274                .map_err(|_| Error::SeekKernelStart)?;
275
276            // if the vmm does not specify where the kernel should be loaded, just
277            // load it to the physical address p_paddr for each segment.
278            let mem_offset = match kernel_offset {
279                Some(k_offset) => k_offset
280                    .checked_add(phdr.p_paddr)
281                    .ok_or(Error::InvalidProgramHeaderAddress)?,
282                None => GuestAddress(phdr.p_paddr),
283            };
284
285            guest_mem
286                .read_exact_volatile_from(mem_offset, kernel_image, phdr.p_filesz as usize)
287                .map_err(|_| Error::ReadKernelImage)?;
288
289            let kernel_end = mem_offset
290                .raw_value()
291                .checked_add(phdr.p_memsz as GuestUsize)
292                .ok_or(KernelLoaderError::MemoryOverflow)?;
293            loader_result.kernel_end = std::cmp::max(loader_result.kernel_end, kernel_end);
294        }
295
296        // elf image has no setup_header which is defined for bzImage
297        loader_result.setup_header = None;
298
299        Ok(loader_result)
300    }
301}
302
303// Size of string "Xen", including the terminating NULL.
304const PVH_NOTE_STR_SZ: usize = 4;
305
306/// Examines a supplied elf program header of type `PT_NOTE` to determine if it contains an entry
307/// of type `XEN_ELFNOTE_PHYS32_ENTRY` (0x12). Notes of this type encode a physical 32-bit entry
308/// point address into the kernel, which is used when launching guests in 32-bit (protected) mode
309/// with paging disabled, as described by the PVH boot protocol.
310/// Returns the encoded entry point address, or `None` if no `XEN_ELFNOTE_PHYS32_ENTRY` entries
311/// are found in the note header.
312fn parse_elf_note<F>(phdr: &elf::Elf64_Phdr, kernel_image: &mut F) -> Result<PvhBootCapability>
313where
314    F: Read + ReadVolatile + Seek,
315{
316    // Type of note header that encodes a 32-bit entry point address to boot a guest kernel using
317    // the PVH boot protocol.
318    const XEN_ELFNOTE_PHYS32_ENTRY: u32 = 18;
319
320    // Alignment of ELF notes, starting address of name field and descriptor field have a 4-byte
321    // alignment.
322    //
323    // See refer from:
324    //  - 'Note Section' of 'Executable and Linking Format (ELF) Specification' v1.2.
325    //  - Linux implementations, https://elixir.bootlin.com/linux/v6.1/source/include/linux/elfnote.h#L56
326    const ELFNOTE_ALIGN: u64 = 4;
327
328    // Seek to the beginning of the note segment.
329    kernel_image
330        .seek(SeekFrom::Start(phdr.p_offset))
331        .map_err(|_| Error::SeekNoteHeader)?;
332
333    // Now that the segment has been found, we must locate an ELF note with the correct type that
334    // encodes the PVH entry point if there is one.
335    let mut nhdr: elf::Elf64_Nhdr = Default::default();
336    let mut read_size: usize = 0;
337    let nhdr_sz = mem::size_of::<elf::Elf64_Nhdr>();
338
339    while read_size < phdr.p_filesz as usize {
340        kernel_image
341            .read_exact(nhdr.as_mut_slice())
342            .map_err(|_| Error::ReadNoteHeader)?;
343
344        // Check if the note header's name and type match the ones specified by the PVH ABI.
345        if nhdr.n_type == XEN_ELFNOTE_PHYS32_ENTRY && nhdr.n_namesz as usize == PVH_NOTE_STR_SZ {
346            let mut buf = [0u8; PVH_NOTE_STR_SZ];
347            kernel_image
348                .read_exact(&mut buf)
349                .map_err(|_| Error::ReadNoteHeader)?;
350            if buf == [b'X', b'e', b'n', b'\0'] {
351                break;
352            }
353        }
354
355        // Skip the note header plus the size of its fields (with alignment).
356        let namesz_aligned = align_up(u64::from(nhdr.n_namesz), ELFNOTE_ALIGN)?;
357        let descsz_aligned = align_up(u64::from(nhdr.n_descsz), ELFNOTE_ALIGN)?;
358
359        // `namesz` and `descsz` are both `u32`s. We need to also verify for overflow, to be sure
360        // we do not lose information.
361        if namesz_aligned > u32::MAX.into() || descsz_aligned > u32::MAX.into() {
362            return Err(Error::Overflow.into());
363        }
364
365        read_size = read_size
366            .checked_add(nhdr_sz) // Skip the ELF_NOTE known sized fields.
367            // Safe to truncate or change the type to `usize` (4 or 8 bytes depending on the
368            // architecture 32/64 bits) since we validated that we do not lose information.
369            .and_then(|read_size| read_size.checked_add(namesz_aligned as usize))
370            .and_then(|read_size| read_size.checked_add(descsz_aligned as usize))
371            .ok_or(Error::Overflow)?;
372
373        kernel_image
374            // The conversion here does not truncate, since `read_size` is of `usize` type, which
375            // can be at maximum 8 bytes long.
376            .seek(SeekFrom::Start(phdr.p_offset + read_size as u64))
377            .map_err(|_| Error::SeekNoteHeader)?;
378    }
379
380    if read_size >= phdr.p_filesz as usize {
381        // PVH ELF note not found, nothing else to do.
382        return Ok(PvhBootCapability::PvhEntryNotPresent);
383    }
384
385    // Otherwise the correct note type was found.
386    // The note header struct has already been read, so we can seek from the current position and
387    // just skip the name field contents.
388    kernel_image
389        .seek(SeekFrom::Current(
390            // Safe conversion since it is not losing data.
391            align_up(u64::from(nhdr.n_namesz), ELFNOTE_ALIGN)? as i64 - PVH_NOTE_STR_SZ as i64,
392        ))
393        .map_err(|_| Error::SeekNoteHeader)?;
394
395    // The PVH entry point is a 32-bit address, so the descriptor field must be capable of storing
396    // all such addresses.
397    if (nhdr.n_descsz as usize) < mem::size_of::<u32>() {
398        return Err(Error::InvalidPvhNote.into());
399    }
400
401    let mut pvh_addr_bytes = [0; mem::size_of::<u32>()];
402
403    // Read 32-bit address stored in the PVH note descriptor field.
404    kernel_image
405        .read_exact(&mut pvh_addr_bytes)
406        .map_err(|_| Error::ReadNoteHeader)?;
407
408    Ok(PvhBootCapability::PvhEntryPresent(GuestAddress(
409        u32::from_le_bytes(pvh_addr_bytes).into(),
410    )))
411}
412
413/// Align address upwards. Adapted from x86_64 crate:
414/// https://docs.rs/x86_64/latest/x86_64/addr/fn.align_up.html
415///
416/// Returns the smallest x with alignment `align` so that x >= addr if the alignment is a power of
417/// 2, or an error otherwise.
418fn align_up(addr: u64, align: u64) -> result::Result<u64, Error> {
419    if !align.is_power_of_two() {
420        return Err(Error::Align);
421    }
422    let align_mask = align - 1;
423    if addr & align_mask == 0 {
424        Ok(addr) // already aligned
425    } else {
426        // Safe to unchecked add because this can be at maximum `2^64` - 1, which is not
427        // overflowing.
428        Ok((addr | align_mask) + 1)
429    }
430}
431
432#[cfg(test)]
433mod tests {
434    use super::*;
435    use std::io::Cursor;
436    use vm_memory::{Address, GuestAddress};
437    type GuestMemoryMmap = vm_memory::GuestMemoryMmap<()>;
438
439    const MEM_SIZE: u64 = 0x100_0000;
440
441    fn create_guest_mem() -> GuestMemoryMmap {
442        GuestMemoryMmap::from_ranges(&[(GuestAddress(0x0), (MEM_SIZE as usize))]).unwrap()
443    }
444
445    fn make_elf_bin() -> Vec<u8> {
446        let mut v = Vec::new();
447        v.extend_from_slice(include_bytes!("test_elf.bin"));
448        v
449    }
450
451    fn make_elfnote() -> Vec<u8> {
452        include_bytes!("test_elfnote.bin").to_vec()
453    }
454
455    fn make_elfnote_8byte_align() -> Vec<u8> {
456        include_bytes!("test_elfnote_8byte_align.bin").to_vec()
457    }
458
459    fn make_dummy_elfnote() -> Vec<u8> {
460        include_bytes!("test_dummy_note.bin").to_vec()
461    }
462
463    fn make_invalid_pvh_note() -> Vec<u8> {
464        include_bytes!("test_invalid_pvh_note.bin").to_vec()
465    }
466
467    fn make_elfnote_bad_align() -> Vec<u8> {
468        include_bytes!("test_bad_align.bin").to_vec()
469    }
470
471    #[test]
472    fn test_load_elf() {
473        let gm = create_guest_mem();
474        let image = make_elf_bin();
475        let kernel_addr = GuestAddress(0x200000);
476        let mut highmem_start_address = GuestAddress(0x0);
477        let mut loader_result = Elf::load(
478            &gm,
479            Some(kernel_addr),
480            &mut Cursor::new(&image),
481            Some(highmem_start_address),
482        )
483        .unwrap();
484        assert_eq!(loader_result.kernel_load.raw_value(), 0x200400);
485
486        loader_result = Elf::load(&gm, Some(kernel_addr), &mut Cursor::new(&image), None).unwrap();
487        assert_eq!(loader_result.kernel_load.raw_value(), 0x200400);
488
489        loader_result = Elf::load(
490            &gm,
491            None,
492            &mut Cursor::new(&image),
493            Some(highmem_start_address),
494        )
495        .unwrap();
496        assert_eq!(loader_result.kernel_load.raw_value(), 0x400);
497
498        highmem_start_address = GuestAddress(0xa00000);
499        assert_eq!(
500            Some(KernelLoaderError::Elf(Error::InvalidEntryAddress)),
501            Elf::load(
502                &gm,
503                None,
504                &mut Cursor::new(&image),
505                Some(highmem_start_address)
506            )
507            .err()
508        );
509    }
510
511    #[test]
512    fn test_bad_magic_number() {
513        let gm = create_guest_mem();
514        let kernel_addr = GuestAddress(0x0);
515        let mut bad_image = make_elf_bin();
516        bad_image[0x1] = 0x33;
517        assert_eq!(
518            Some(KernelLoaderError::Elf(Error::InvalidElfMagicNumber)),
519            Elf::load(&gm, Some(kernel_addr), &mut Cursor::new(&bad_image), None).err()
520        );
521    }
522
523    #[test]
524    fn test_bad_endian() {
525        // Only little endian is supported.
526        let gm = create_guest_mem();
527        let kernel_addr = GuestAddress(0x0);
528        let mut bad_image = make_elf_bin();
529        bad_image[0x5] = 2;
530        assert_eq!(
531            Some(KernelLoaderError::Elf(Error::BigEndianElfOnLittle)),
532            Elf::load(&gm, Some(kernel_addr), &mut Cursor::new(&bad_image), None).err()
533        );
534    }
535
536    #[test]
537    fn test_bad_phoff() {
538        // Program header has to be past the end of the elf header.
539        let gm = create_guest_mem();
540        let kernel_addr = GuestAddress(0x0);
541        let mut bad_image = make_elf_bin();
542        bad_image[0x20] = 0x10;
543        assert_eq!(
544            Some(KernelLoaderError::Elf(Error::InvalidProgramHeaderOffset)),
545            Elf::load(&gm, Some(kernel_addr), &mut Cursor::new(&bad_image), None).err()
546        );
547    }
548
549    #[test]
550    fn test_load_pvh() {
551        let gm = create_guest_mem();
552        let pvhnote_image = make_elfnote();
553        let loader_result = Elf::load(&gm, None, &mut Cursor::new(&pvhnote_image), None).unwrap();
554        assert_eq!(
555            loader_result.pvh_boot_cap,
556            PvhBootCapability::PvhEntryPresent(GuestAddress(0x1e1fe1f))
557        );
558
559        // Verify that PVH is ignored when kernel_start is requested
560        let loader_result = Elf::load(
561            &gm,
562            Some(GuestAddress(0x0020_0000)),
563            &mut Cursor::new(&pvhnote_image),
564            None,
565        )
566        .unwrap();
567        assert_eq!(
568            loader_result.pvh_boot_cap,
569            PvhBootCapability::PvhEntryIgnored
570        );
571    }
572
573    #[test]
574    fn test_dummy_elfnote() {
575        let gm = create_guest_mem();
576        let dummynote_image = make_dummy_elfnote();
577        let loader_result = Elf::load(&gm, None, &mut Cursor::new(&dummynote_image), None).unwrap();
578        assert_eq!(
579            loader_result.pvh_boot_cap,
580            PvhBootCapability::PvhEntryNotPresent
581        );
582    }
583
584    #[test]
585    fn test_bad_elfnote() {
586        let gm = create_guest_mem();
587        let badnote_image = make_invalid_pvh_note();
588        assert_eq!(
589            Some(KernelLoaderError::Elf(Error::InvalidPvhNote)),
590            Elf::load(&gm, None, &mut Cursor::new(&badnote_image), None).err()
591        );
592    }
593
594    #[test]
595    fn test_load_pvh_with_align() {
596        // Alignment of ELF notes is always const value (4-bytes), ELF notes parse should not get Align
597        // error.
598        {
599            let gm =
600                GuestMemoryMmap::from_ranges(&[(GuestAddress(0x0), (0x1000_0000_usize))]).unwrap();
601            let bad_align_image = make_elfnote_bad_align();
602            assert_ne!(
603                Some(KernelLoaderError::Elf(Error::Align)),
604                Elf::load(&gm, None, &mut Cursor::new(&bad_align_image), None).err()
605            );
606        }
607
608        // Alignment of ELF notes is always const value (4-byte), ELF notes parse should always
609        // success even there is incorrect p_align in phdr.
610        {
611            let gm = create_guest_mem();
612            let pvhnote_image = make_elfnote_8byte_align();
613            let loader_result =
614                Elf::load(&gm, None, &mut Cursor::new(&pvhnote_image), None).unwrap();
615            assert_eq!(
616                loader_result.pvh_boot_cap,
617                PvhBootCapability::PvhEntryPresent(GuestAddress(0x1e1fe1f))
618            );
619        }
620    }
621
622    #[test]
623    fn test_overflow_loadaddr() {
624        let gm = create_guest_mem();
625        let image = make_elf_bin();
626        assert_eq!(
627            Some(KernelLoaderError::Elf(Error::Overflow)),
628            Elf::load(
629                &gm,
630                Some(GuestAddress(u64::MAX)),
631                &mut Cursor::new(&image),
632                None
633            )
634            .err()
635        );
636    }
637}