xref: /aosp_15_r20/external/crosvm/kernel_loader/src/lib.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2017 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! Linux kernel ELF file loader.
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use std::mem;
8*bb4ee6a4SAndroid Build Coastguard Worker 
9*bb4ee6a4SAndroid Build Coastguard Worker use base::FileReadWriteAtVolatile;
10*bb4ee6a4SAndroid Build Coastguard Worker use base::VolatileSlice;
11*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
12*bb4ee6a4SAndroid Build Coastguard Worker use resources::AddressRange;
13*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error;
14*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
15*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
16*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
17*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes;
18*bb4ee6a4SAndroid Build Coastguard Worker 
19*bb4ee6a4SAndroid Build Coastguard Worker mod multiboot;
20*bb4ee6a4SAndroid Build Coastguard Worker 
21*bb4ee6a4SAndroid Build Coastguard Worker #[allow(dead_code)]
22*bb4ee6a4SAndroid Build Coastguard Worker #[allow(non_camel_case_types)]
23*bb4ee6a4SAndroid Build Coastguard Worker #[allow(non_snake_case)]
24*bb4ee6a4SAndroid Build Coastguard Worker #[allow(non_upper_case_globals)]
25*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::all)]
26*bb4ee6a4SAndroid Build Coastguard Worker mod elf;
27*bb4ee6a4SAndroid Build Coastguard Worker 
28*bb4ee6a4SAndroid Build Coastguard Worker mod arm64;
29*bb4ee6a4SAndroid Build Coastguard Worker 
30*bb4ee6a4SAndroid Build Coastguard Worker pub use arm64::load_arm64_kernel;
31*bb4ee6a4SAndroid Build Coastguard Worker pub use arm64::load_arm64_kernel_lz4;
32*bb4ee6a4SAndroid Build Coastguard Worker pub use multiboot::load_multiboot;
33*bb4ee6a4SAndroid Build Coastguard Worker pub use multiboot::multiboot_header_from_file;
34*bb4ee6a4SAndroid Build Coastguard Worker 
35*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
36*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug, PartialEq, Eq)]
37*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error {
38*bb4ee6a4SAndroid Build Coastguard Worker     #[error("trying to load big-endian binary on little-endian machine")]
39*bb4ee6a4SAndroid Build Coastguard Worker     BigEndianOnLittle,
40*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid elf class")]
41*bb4ee6a4SAndroid Build Coastguard Worker     InvalidElfClass,
42*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid elf version")]
43*bb4ee6a4SAndroid Build Coastguard Worker     InvalidElfVersion,
44*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid entry point")]
45*bb4ee6a4SAndroid Build Coastguard Worker     InvalidEntryPoint,
46*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid flags")]
47*bb4ee6a4SAndroid Build Coastguard Worker     InvalidFlags,
48*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid kernel offset")]
49*bb4ee6a4SAndroid Build Coastguard Worker     InvalidKernelOffset,
50*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid kernel size")]
51*bb4ee6a4SAndroid Build Coastguard Worker     InvalidKernelSize,
52*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid magic number")]
53*bb4ee6a4SAndroid Build Coastguard Worker     InvalidMagicNumber,
54*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid Program Header Address")]
55*bb4ee6a4SAndroid Build Coastguard Worker     InvalidProgramHeaderAddress,
56*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid Program Header memory size")]
57*bb4ee6a4SAndroid Build Coastguard Worker     InvalidProgramHeaderMemSize,
58*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid program header offset")]
59*bb4ee6a4SAndroid Build Coastguard Worker     InvalidProgramHeaderOffset,
60*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid program header size")]
61*bb4ee6a4SAndroid Build Coastguard Worker     InvalidProgramHeaderSize,
62*bb4ee6a4SAndroid Build Coastguard Worker     #[error("no loadable program headers found")]
63*bb4ee6a4SAndroid Build Coastguard Worker     NoLoadableProgramHeaders,
64*bb4ee6a4SAndroid Build Coastguard Worker     #[error("program header address out of allowed address range")]
65*bb4ee6a4SAndroid Build Coastguard Worker     ProgramHeaderAddressOutOfRange,
66*bb4ee6a4SAndroid Build Coastguard Worker     #[error("unable to read header")]
67*bb4ee6a4SAndroid Build Coastguard Worker     ReadHeader,
68*bb4ee6a4SAndroid Build Coastguard Worker     #[error("unable to read kernel image")]
69*bb4ee6a4SAndroid Build Coastguard Worker     ReadKernelImage,
70*bb4ee6a4SAndroid Build Coastguard Worker     #[error("unable to read program header")]
71*bb4ee6a4SAndroid Build Coastguard Worker     ReadProgramHeader,
72*bb4ee6a4SAndroid Build Coastguard Worker     #[error("unable to seek to kernel end")]
73*bb4ee6a4SAndroid Build Coastguard Worker     SeekKernelEnd,
74*bb4ee6a4SAndroid Build Coastguard Worker     #[error("unable to seek to kernel start")]
75*bb4ee6a4SAndroid Build Coastguard Worker     SeekKernelStart,
76*bb4ee6a4SAndroid Build Coastguard Worker     #[error("unable to seek to program header")]
77*bb4ee6a4SAndroid Build Coastguard Worker     SeekProgramHeader,
78*bb4ee6a4SAndroid Build Coastguard Worker }
79*bb4ee6a4SAndroid Build Coastguard Worker pub type Result<T> = std::result::Result<T, Error>;
80*bb4ee6a4SAndroid Build Coastguard Worker 
81*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Copy, Clone, PartialEq, Eq)]
82*bb4ee6a4SAndroid Build Coastguard Worker /// Information about a kernel loaded with the [`load_elf`] function.
83*bb4ee6a4SAndroid Build Coastguard Worker pub struct LoadedKernel {
84*bb4ee6a4SAndroid Build Coastguard Worker     /// Address range containg the bounds of the loaded program headers.
85*bb4ee6a4SAndroid Build Coastguard Worker     /// `address_range.start` is the start of the lowest loaded program header.
86*bb4ee6a4SAndroid Build Coastguard Worker     /// `address_range.end` is the end of the highest loaded program header.
87*bb4ee6a4SAndroid Build Coastguard Worker     pub address_range: AddressRange,
88*bb4ee6a4SAndroid Build Coastguard Worker 
89*bb4ee6a4SAndroid Build Coastguard Worker     /// Size of the kernel image in bytes.
90*bb4ee6a4SAndroid Build Coastguard Worker     pub size: u64,
91*bb4ee6a4SAndroid Build Coastguard Worker 
92*bb4ee6a4SAndroid Build Coastguard Worker     /// Entry point address of the kernel.
93*bb4ee6a4SAndroid Build Coastguard Worker     pub entry: GuestAddress,
94*bb4ee6a4SAndroid Build Coastguard Worker }
95*bb4ee6a4SAndroid Build Coastguard Worker 
96*bb4ee6a4SAndroid Build Coastguard Worker /// Loads a kernel from a 32-bit ELF image into memory.
97*bb4ee6a4SAndroid Build Coastguard Worker ///
98*bb4ee6a4SAndroid Build Coastguard Worker /// The ELF file will be loaded at the physical address specified by the `p_paddr` fields of its
99*bb4ee6a4SAndroid Build Coastguard Worker /// program headers.
100*bb4ee6a4SAndroid Build Coastguard Worker ///
101*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
102*bb4ee6a4SAndroid Build Coastguard Worker ///
103*bb4ee6a4SAndroid Build Coastguard Worker /// * `guest_mem` - The guest memory region the kernel is written to.
104*bb4ee6a4SAndroid Build Coastguard Worker /// * `kernel_start` - The minimum guest address to allow when loading program headers.
105*bb4ee6a4SAndroid Build Coastguard Worker /// * `kernel_image` - Input vmlinux image.
106*bb4ee6a4SAndroid Build Coastguard Worker /// * `phys_offset` - An offset in bytes to add to each physical address (`p_paddr`).
load_elf32<F>( guest_mem: &GuestMemory, kernel_start: GuestAddress, kernel_image: &mut F, phys_offset: u64, ) -> Result<LoadedKernel> where F: FileReadWriteAtVolatile,107*bb4ee6a4SAndroid Build Coastguard Worker pub fn load_elf32<F>(
108*bb4ee6a4SAndroid Build Coastguard Worker     guest_mem: &GuestMemory,
109*bb4ee6a4SAndroid Build Coastguard Worker     kernel_start: GuestAddress,
110*bb4ee6a4SAndroid Build Coastguard Worker     kernel_image: &mut F,
111*bb4ee6a4SAndroid Build Coastguard Worker     phys_offset: u64,
112*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<LoadedKernel>
113*bb4ee6a4SAndroid Build Coastguard Worker where
114*bb4ee6a4SAndroid Build Coastguard Worker     F: FileReadWriteAtVolatile,
115*bb4ee6a4SAndroid Build Coastguard Worker {
116*bb4ee6a4SAndroid Build Coastguard Worker     load_elf_for_class(
117*bb4ee6a4SAndroid Build Coastguard Worker         guest_mem,
118*bb4ee6a4SAndroid Build Coastguard Worker         kernel_start,
119*bb4ee6a4SAndroid Build Coastguard Worker         kernel_image,
120*bb4ee6a4SAndroid Build Coastguard Worker         phys_offset,
121*bb4ee6a4SAndroid Build Coastguard Worker         Some(elf::ELFCLASS32),
122*bb4ee6a4SAndroid Build Coastguard Worker     )
123*bb4ee6a4SAndroid Build Coastguard Worker }
124*bb4ee6a4SAndroid Build Coastguard Worker 
125*bb4ee6a4SAndroid Build Coastguard Worker /// Loads a kernel from a 64-bit ELF image into memory.
126*bb4ee6a4SAndroid Build Coastguard Worker ///
127*bb4ee6a4SAndroid Build Coastguard Worker /// The ELF file will be loaded at the physical address specified by the `p_paddr` fields of its
128*bb4ee6a4SAndroid Build Coastguard Worker /// program headers.
129*bb4ee6a4SAndroid Build Coastguard Worker ///
130*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
131*bb4ee6a4SAndroid Build Coastguard Worker ///
132*bb4ee6a4SAndroid Build Coastguard Worker /// * `guest_mem` - The guest memory region the kernel is written to.
133*bb4ee6a4SAndroid Build Coastguard Worker /// * `kernel_start` - The minimum guest address to allow when loading program headers.
134*bb4ee6a4SAndroid Build Coastguard Worker /// * `kernel_image` - Input vmlinux image.
135*bb4ee6a4SAndroid Build Coastguard Worker /// * `phys_offset` - An offset in bytes to add to each physical address (`p_paddr`).
load_elf64<F>( guest_mem: &GuestMemory, kernel_start: GuestAddress, kernel_image: &mut F, phys_offset: u64, ) -> Result<LoadedKernel> where F: FileReadWriteAtVolatile,136*bb4ee6a4SAndroid Build Coastguard Worker pub fn load_elf64<F>(
137*bb4ee6a4SAndroid Build Coastguard Worker     guest_mem: &GuestMemory,
138*bb4ee6a4SAndroid Build Coastguard Worker     kernel_start: GuestAddress,
139*bb4ee6a4SAndroid Build Coastguard Worker     kernel_image: &mut F,
140*bb4ee6a4SAndroid Build Coastguard Worker     phys_offset: u64,
141*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<LoadedKernel>
142*bb4ee6a4SAndroid Build Coastguard Worker where
143*bb4ee6a4SAndroid Build Coastguard Worker     F: FileReadWriteAtVolatile,
144*bb4ee6a4SAndroid Build Coastguard Worker {
145*bb4ee6a4SAndroid Build Coastguard Worker     load_elf_for_class(
146*bb4ee6a4SAndroid Build Coastguard Worker         guest_mem,
147*bb4ee6a4SAndroid Build Coastguard Worker         kernel_start,
148*bb4ee6a4SAndroid Build Coastguard Worker         kernel_image,
149*bb4ee6a4SAndroid Build Coastguard Worker         phys_offset,
150*bb4ee6a4SAndroid Build Coastguard Worker         Some(elf::ELFCLASS64),
151*bb4ee6a4SAndroid Build Coastguard Worker     )
152*bb4ee6a4SAndroid Build Coastguard Worker }
153*bb4ee6a4SAndroid Build Coastguard Worker 
154*bb4ee6a4SAndroid Build Coastguard Worker /// Loads a kernel from a 32-bit or 64-bit ELF image into memory.
155*bb4ee6a4SAndroid Build Coastguard Worker ///
156*bb4ee6a4SAndroid Build Coastguard Worker /// The ELF file will be loaded at the physical address specified by the `p_paddr` fields of its
157*bb4ee6a4SAndroid Build Coastguard Worker /// program headers.
158*bb4ee6a4SAndroid Build Coastguard Worker ///
159*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
160*bb4ee6a4SAndroid Build Coastguard Worker ///
161*bb4ee6a4SAndroid Build Coastguard Worker /// * `guest_mem` - The guest memory region the kernel is written to.
162*bb4ee6a4SAndroid Build Coastguard Worker /// * `kernel_start` - The minimum guest address to allow when loading program headers.
163*bb4ee6a4SAndroid Build Coastguard Worker /// * `kernel_image` - Input vmlinux image.
164*bb4ee6a4SAndroid Build Coastguard Worker /// * `phys_offset` - An offset in bytes to add to each physical address (`p_paddr`).
load_elf<F>( guest_mem: &GuestMemory, kernel_start: GuestAddress, kernel_image: &mut F, phys_offset: u64, ) -> Result<LoadedKernel> where F: FileReadWriteAtVolatile,165*bb4ee6a4SAndroid Build Coastguard Worker pub fn load_elf<F>(
166*bb4ee6a4SAndroid Build Coastguard Worker     guest_mem: &GuestMemory,
167*bb4ee6a4SAndroid Build Coastguard Worker     kernel_start: GuestAddress,
168*bb4ee6a4SAndroid Build Coastguard Worker     kernel_image: &mut F,
169*bb4ee6a4SAndroid Build Coastguard Worker     phys_offset: u64,
170*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<LoadedKernel>
171*bb4ee6a4SAndroid Build Coastguard Worker where
172*bb4ee6a4SAndroid Build Coastguard Worker     F: FileReadWriteAtVolatile,
173*bb4ee6a4SAndroid Build Coastguard Worker {
174*bb4ee6a4SAndroid Build Coastguard Worker     load_elf_for_class(guest_mem, kernel_start, kernel_image, phys_offset, None)
175*bb4ee6a4SAndroid Build Coastguard Worker }
176*bb4ee6a4SAndroid Build Coastguard Worker 
load_elf_for_class<F>( guest_mem: &GuestMemory, kernel_start: GuestAddress, kernel_image: &mut F, phys_offset: u64, ei_class: Option<u32>, ) -> Result<LoadedKernel> where F: FileReadWriteAtVolatile,177*bb4ee6a4SAndroid Build Coastguard Worker fn load_elf_for_class<F>(
178*bb4ee6a4SAndroid Build Coastguard Worker     guest_mem: &GuestMemory,
179*bb4ee6a4SAndroid Build Coastguard Worker     kernel_start: GuestAddress,
180*bb4ee6a4SAndroid Build Coastguard Worker     kernel_image: &mut F,
181*bb4ee6a4SAndroid Build Coastguard Worker     phys_offset: u64,
182*bb4ee6a4SAndroid Build Coastguard Worker     ei_class: Option<u32>,
183*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<LoadedKernel>
184*bb4ee6a4SAndroid Build Coastguard Worker where
185*bb4ee6a4SAndroid Build Coastguard Worker     F: FileReadWriteAtVolatile,
186*bb4ee6a4SAndroid Build Coastguard Worker {
187*bb4ee6a4SAndroid Build Coastguard Worker     let elf = read_elf(kernel_image, ei_class)?;
188*bb4ee6a4SAndroid Build Coastguard Worker     let mut start = None;
189*bb4ee6a4SAndroid Build Coastguard Worker     let mut end = 0;
190*bb4ee6a4SAndroid Build Coastguard Worker 
191*bb4ee6a4SAndroid Build Coastguard Worker     // Read in each section pointed to by the program headers.
192*bb4ee6a4SAndroid Build Coastguard Worker     for phdr in &elf.program_headers {
193*bb4ee6a4SAndroid Build Coastguard Worker         if phdr.p_type != elf::PT_LOAD {
194*bb4ee6a4SAndroid Build Coastguard Worker             continue;
195*bb4ee6a4SAndroid Build Coastguard Worker         }
196*bb4ee6a4SAndroid Build Coastguard Worker 
197*bb4ee6a4SAndroid Build Coastguard Worker         let paddr = phdr
198*bb4ee6a4SAndroid Build Coastguard Worker             .p_paddr
199*bb4ee6a4SAndroid Build Coastguard Worker             .checked_add(phys_offset)
200*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or(Error::ProgramHeaderAddressOutOfRange)?;
201*bb4ee6a4SAndroid Build Coastguard Worker 
202*bb4ee6a4SAndroid Build Coastguard Worker         if paddr < kernel_start.offset() {
203*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::ProgramHeaderAddressOutOfRange);
204*bb4ee6a4SAndroid Build Coastguard Worker         }
205*bb4ee6a4SAndroid Build Coastguard Worker 
206*bb4ee6a4SAndroid Build Coastguard Worker         if start.is_none() {
207*bb4ee6a4SAndroid Build Coastguard Worker             start = Some(paddr);
208*bb4ee6a4SAndroid Build Coastguard Worker         }
209*bb4ee6a4SAndroid Build Coastguard Worker 
210*bb4ee6a4SAndroid Build Coastguard Worker         end = paddr
211*bb4ee6a4SAndroid Build Coastguard Worker             .checked_add(phdr.p_memsz)
212*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or(Error::InvalidProgramHeaderMemSize)?;
213*bb4ee6a4SAndroid Build Coastguard Worker 
214*bb4ee6a4SAndroid Build Coastguard Worker         if phdr.p_filesz == 0 {
215*bb4ee6a4SAndroid Build Coastguard Worker             continue;
216*bb4ee6a4SAndroid Build Coastguard Worker         }
217*bb4ee6a4SAndroid Build Coastguard Worker 
218*bb4ee6a4SAndroid Build Coastguard Worker         let guest_slice = guest_mem
219*bb4ee6a4SAndroid Build Coastguard Worker             .get_slice_at_addr(GuestAddress(paddr), phdr.p_filesz as usize)
220*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(|_| Error::ReadKernelImage)?;
221*bb4ee6a4SAndroid Build Coastguard Worker         kernel_image
222*bb4ee6a4SAndroid Build Coastguard Worker             .read_exact_at_volatile(guest_slice, phdr.p_offset)
223*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(|_| Error::ReadKernelImage)?;
224*bb4ee6a4SAndroid Build Coastguard Worker     }
225*bb4ee6a4SAndroid Build Coastguard Worker 
226*bb4ee6a4SAndroid Build Coastguard Worker     // We should have found at least one PT_LOAD program header. If not, `start` will not be set.
227*bb4ee6a4SAndroid Build Coastguard Worker     let start = start.ok_or(Error::NoLoadableProgramHeaders)?;
228*bb4ee6a4SAndroid Build Coastguard Worker 
229*bb4ee6a4SAndroid Build Coastguard Worker     let size = end
230*bb4ee6a4SAndroid Build Coastguard Worker         .checked_sub(start)
231*bb4ee6a4SAndroid Build Coastguard Worker         .ok_or(Error::InvalidProgramHeaderSize)?;
232*bb4ee6a4SAndroid Build Coastguard Worker 
233*bb4ee6a4SAndroid Build Coastguard Worker     let address_range = AddressRange { start, end };
234*bb4ee6a4SAndroid Build Coastguard Worker 
235*bb4ee6a4SAndroid Build Coastguard Worker     // The entry point address must fall within one of the loaded sections.
236*bb4ee6a4SAndroid Build Coastguard Worker     // We approximate this by checking whether it within the bounds of the first and last sections.
237*bb4ee6a4SAndroid Build Coastguard Worker     let entry = elf
238*bb4ee6a4SAndroid Build Coastguard Worker         .file_header
239*bb4ee6a4SAndroid Build Coastguard Worker         .e_entry
240*bb4ee6a4SAndroid Build Coastguard Worker         .checked_add(phys_offset)
241*bb4ee6a4SAndroid Build Coastguard Worker         .ok_or(Error::InvalidEntryPoint)?;
242*bb4ee6a4SAndroid Build Coastguard Worker     if !address_range.contains(entry) {
243*bb4ee6a4SAndroid Build Coastguard Worker         return Err(Error::InvalidEntryPoint);
244*bb4ee6a4SAndroid Build Coastguard Worker     }
245*bb4ee6a4SAndroid Build Coastguard Worker 
246*bb4ee6a4SAndroid Build Coastguard Worker     Ok(LoadedKernel {
247*bb4ee6a4SAndroid Build Coastguard Worker         address_range,
248*bb4ee6a4SAndroid Build Coastguard Worker         size,
249*bb4ee6a4SAndroid Build Coastguard Worker         entry: GuestAddress(entry),
250*bb4ee6a4SAndroid Build Coastguard Worker     })
251*bb4ee6a4SAndroid Build Coastguard Worker }
252*bb4ee6a4SAndroid Build Coastguard Worker 
253*bb4ee6a4SAndroid Build Coastguard Worker struct Elf64 {
254*bb4ee6a4SAndroid Build Coastguard Worker     file_header: elf::Elf64_Ehdr,
255*bb4ee6a4SAndroid Build Coastguard Worker     program_headers: Vec<elf::Elf64_Phdr>,
256*bb4ee6a4SAndroid Build Coastguard Worker }
257*bb4ee6a4SAndroid Build Coastguard Worker 
258*bb4ee6a4SAndroid Build Coastguard Worker /// Reads the headers of an ELF32 or ELF64 object file.  Returns ELF file and program headers,
259*bb4ee6a4SAndroid Build Coastguard Worker /// converted to ELF64 format.  If `required_ei_class` is Some and the file's ELF ei_class doesn't
260*bb4ee6a4SAndroid Build Coastguard Worker /// match, an Err is returned.
read_elf<F>(file: &mut F, required_ei_class: Option<u32>) -> Result<Elf64> where F: FileReadWriteAtVolatile,261*bb4ee6a4SAndroid Build Coastguard Worker fn read_elf<F>(file: &mut F, required_ei_class: Option<u32>) -> Result<Elf64>
262*bb4ee6a4SAndroid Build Coastguard Worker where
263*bb4ee6a4SAndroid Build Coastguard Worker     F: FileReadWriteAtVolatile,
264*bb4ee6a4SAndroid Build Coastguard Worker {
265*bb4ee6a4SAndroid Build Coastguard Worker     // Read the ELF identification (e_ident) block.
266*bb4ee6a4SAndroid Build Coastguard Worker     let mut ident = [0u8; 16];
267*bb4ee6a4SAndroid Build Coastguard Worker     file.read_exact_at_volatile(VolatileSlice::new(&mut ident), 0)
268*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(|_| Error::ReadHeader)?;
269*bb4ee6a4SAndroid Build Coastguard Worker 
270*bb4ee6a4SAndroid Build Coastguard Worker     // e_ident checks
271*bb4ee6a4SAndroid Build Coastguard Worker     if ident[elf::EI_MAG0 as usize] != elf::ELFMAG0 as u8
272*bb4ee6a4SAndroid Build Coastguard Worker         || ident[elf::EI_MAG1 as usize] != elf::ELFMAG1
273*bb4ee6a4SAndroid Build Coastguard Worker         || ident[elf::EI_MAG2 as usize] != elf::ELFMAG2
274*bb4ee6a4SAndroid Build Coastguard Worker         || ident[elf::EI_MAG3 as usize] != elf::ELFMAG3
275*bb4ee6a4SAndroid Build Coastguard Worker     {
276*bb4ee6a4SAndroid Build Coastguard Worker         return Err(Error::InvalidMagicNumber);
277*bb4ee6a4SAndroid Build Coastguard Worker     }
278*bb4ee6a4SAndroid Build Coastguard Worker     if ident[elf::EI_DATA as usize] != elf::ELFDATA2LSB as u8 {
279*bb4ee6a4SAndroid Build Coastguard Worker         return Err(Error::BigEndianOnLittle);
280*bb4ee6a4SAndroid Build Coastguard Worker     }
281*bb4ee6a4SAndroid Build Coastguard Worker     if ident[elf::EI_VERSION as usize] != elf::EV_CURRENT as u8 {
282*bb4ee6a4SAndroid Build Coastguard Worker         return Err(Error::InvalidElfVersion);
283*bb4ee6a4SAndroid Build Coastguard Worker     }
284*bb4ee6a4SAndroid Build Coastguard Worker 
285*bb4ee6a4SAndroid Build Coastguard Worker     let ei_class = ident[elf::EI_CLASS as usize] as u32;
286*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(required_ei_class) = required_ei_class {
287*bb4ee6a4SAndroid Build Coastguard Worker         if ei_class != required_ei_class {
288*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::InvalidElfClass);
289*bb4ee6a4SAndroid Build Coastguard Worker         }
290*bb4ee6a4SAndroid Build Coastguard Worker     }
291*bb4ee6a4SAndroid Build Coastguard Worker     match ei_class {
292*bb4ee6a4SAndroid Build Coastguard Worker         elf::ELFCLASS32 => read_elf_by_type::<_, elf::Elf32_Ehdr, elf::Elf32_Phdr>(file),
293*bb4ee6a4SAndroid Build Coastguard Worker         elf::ELFCLASS64 => read_elf_by_type::<_, elf::Elf64_Ehdr, elf::Elf64_Phdr>(file),
294*bb4ee6a4SAndroid Build Coastguard Worker         _ => Err(Error::InvalidElfClass),
295*bb4ee6a4SAndroid Build Coastguard Worker     }
296*bb4ee6a4SAndroid Build Coastguard Worker }
297*bb4ee6a4SAndroid Build Coastguard Worker 
298*bb4ee6a4SAndroid Build Coastguard Worker /// Reads the headers of an ELF32 or ELF64 object file.  Returns ELF file and program headers,
299*bb4ee6a4SAndroid Build Coastguard Worker /// converted to ELF64 format.  `FileHeader` and `ProgramHeader` are the ELF32 or ELF64 ehdr/phdr
300*bb4ee6a4SAndroid Build Coastguard Worker /// types to read from the file.  Caller should check that `file` is a valid ELF file before calling
301*bb4ee6a4SAndroid Build Coastguard Worker /// this function.
read_elf_by_type<F, FileHeader, ProgramHeader>(file: &mut F) -> Result<Elf64> where F: FileReadWriteAtVolatile, FileHeader: AsBytes + FromBytes + Default + Into<elf::Elf64_Ehdr>, ProgramHeader: AsBytes + FromBytes + Clone + Default + Into<elf::Elf64_Phdr>,302*bb4ee6a4SAndroid Build Coastguard Worker fn read_elf_by_type<F, FileHeader, ProgramHeader>(file: &mut F) -> Result<Elf64>
303*bb4ee6a4SAndroid Build Coastguard Worker where
304*bb4ee6a4SAndroid Build Coastguard Worker     F: FileReadWriteAtVolatile,
305*bb4ee6a4SAndroid Build Coastguard Worker     FileHeader: AsBytes + FromBytes + Default + Into<elf::Elf64_Ehdr>,
306*bb4ee6a4SAndroid Build Coastguard Worker     ProgramHeader: AsBytes + FromBytes + Clone + Default + Into<elf::Elf64_Phdr>,
307*bb4ee6a4SAndroid Build Coastguard Worker {
308*bb4ee6a4SAndroid Build Coastguard Worker     let mut ehdr = FileHeader::new_zeroed();
309*bb4ee6a4SAndroid Build Coastguard Worker     file.read_exact_at_volatile(VolatileSlice::new(ehdr.as_bytes_mut()), 0)
310*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(|_| Error::ReadHeader)?;
311*bb4ee6a4SAndroid Build Coastguard Worker     let ehdr: elf::Elf64_Ehdr = ehdr.into();
312*bb4ee6a4SAndroid Build Coastguard Worker 
313*bb4ee6a4SAndroid Build Coastguard Worker     if ehdr.e_phentsize as usize != mem::size_of::<ProgramHeader>() {
314*bb4ee6a4SAndroid Build Coastguard Worker         return Err(Error::InvalidProgramHeaderSize);
315*bb4ee6a4SAndroid Build Coastguard Worker     }
316*bb4ee6a4SAndroid Build Coastguard Worker     if (ehdr.e_phoff as usize) < mem::size_of::<FileHeader>() {
317*bb4ee6a4SAndroid Build Coastguard Worker         // If the program header is backwards, bail.
318*bb4ee6a4SAndroid Build Coastguard Worker         return Err(Error::InvalidProgramHeaderOffset);
319*bb4ee6a4SAndroid Build Coastguard Worker     }
320*bb4ee6a4SAndroid Build Coastguard Worker 
321*bb4ee6a4SAndroid Build Coastguard Worker     let num_phdrs = ehdr.e_phnum as usize;
322*bb4ee6a4SAndroid Build Coastguard Worker     let mut phdrs = vec![ProgramHeader::default(); num_phdrs];
323*bb4ee6a4SAndroid Build Coastguard Worker     file.read_exact_at_volatile(VolatileSlice::new(phdrs.as_bytes_mut()), ehdr.e_phoff)
324*bb4ee6a4SAndroid Build Coastguard Worker         .map_err(|_| Error::ReadProgramHeader)?;
325*bb4ee6a4SAndroid Build Coastguard Worker 
326*bb4ee6a4SAndroid Build Coastguard Worker     Ok(Elf64 {
327*bb4ee6a4SAndroid Build Coastguard Worker         file_header: ehdr,
328*bb4ee6a4SAndroid Build Coastguard Worker         program_headers: phdrs.into_iter().map(|ph| ph.into()).collect(),
329*bb4ee6a4SAndroid Build Coastguard Worker     })
330*bb4ee6a4SAndroid Build Coastguard Worker }
331*bb4ee6a4SAndroid Build Coastguard Worker 
332*bb4ee6a4SAndroid Build Coastguard Worker impl From<elf::Elf32_Ehdr> for elf::Elf64_Ehdr {
from(ehdr32: elf::Elf32_Ehdr) -> Self333*bb4ee6a4SAndroid Build Coastguard Worker     fn from(ehdr32: elf::Elf32_Ehdr) -> Self {
334*bb4ee6a4SAndroid Build Coastguard Worker         elf::Elf64_Ehdr {
335*bb4ee6a4SAndroid Build Coastguard Worker             e_ident: ehdr32.e_ident,
336*bb4ee6a4SAndroid Build Coastguard Worker             e_type: ehdr32.e_type as elf::Elf64_Half,
337*bb4ee6a4SAndroid Build Coastguard Worker             e_machine: ehdr32.e_machine as elf::Elf64_Half,
338*bb4ee6a4SAndroid Build Coastguard Worker             e_version: ehdr32.e_version as elf::Elf64_Word,
339*bb4ee6a4SAndroid Build Coastguard Worker             e_entry: ehdr32.e_entry as elf::Elf64_Addr,
340*bb4ee6a4SAndroid Build Coastguard Worker             e_phoff: ehdr32.e_phoff as elf::Elf64_Off,
341*bb4ee6a4SAndroid Build Coastguard Worker             e_shoff: ehdr32.e_shoff as elf::Elf64_Off,
342*bb4ee6a4SAndroid Build Coastguard Worker             e_flags: ehdr32.e_flags as elf::Elf64_Word,
343*bb4ee6a4SAndroid Build Coastguard Worker             e_ehsize: ehdr32.e_ehsize as elf::Elf64_Half,
344*bb4ee6a4SAndroid Build Coastguard Worker             e_phentsize: ehdr32.e_phentsize as elf::Elf64_Half,
345*bb4ee6a4SAndroid Build Coastguard Worker             e_phnum: ehdr32.e_phnum as elf::Elf64_Half,
346*bb4ee6a4SAndroid Build Coastguard Worker             e_shentsize: ehdr32.e_shentsize as elf::Elf64_Half,
347*bb4ee6a4SAndroid Build Coastguard Worker             e_shnum: ehdr32.e_shnum as elf::Elf64_Half,
348*bb4ee6a4SAndroid Build Coastguard Worker             e_shstrndx: ehdr32.e_shstrndx as elf::Elf64_Half,
349*bb4ee6a4SAndroid Build Coastguard Worker         }
350*bb4ee6a4SAndroid Build Coastguard Worker     }
351*bb4ee6a4SAndroid Build Coastguard Worker }
352*bb4ee6a4SAndroid Build Coastguard Worker 
353*bb4ee6a4SAndroid Build Coastguard Worker impl From<elf::Elf32_Phdr> for elf::Elf64_Phdr {
from(phdr32: elf::Elf32_Phdr) -> Self354*bb4ee6a4SAndroid Build Coastguard Worker     fn from(phdr32: elf::Elf32_Phdr) -> Self {
355*bb4ee6a4SAndroid Build Coastguard Worker         elf::Elf64_Phdr {
356*bb4ee6a4SAndroid Build Coastguard Worker             p_type: phdr32.p_type as elf::Elf64_Word,
357*bb4ee6a4SAndroid Build Coastguard Worker             p_flags: phdr32.p_flags as elf::Elf64_Word,
358*bb4ee6a4SAndroid Build Coastguard Worker             p_offset: phdr32.p_offset as elf::Elf64_Off,
359*bb4ee6a4SAndroid Build Coastguard Worker             p_vaddr: phdr32.p_vaddr as elf::Elf64_Addr,
360*bb4ee6a4SAndroid Build Coastguard Worker             p_paddr: phdr32.p_paddr as elf::Elf64_Addr,
361*bb4ee6a4SAndroid Build Coastguard Worker             p_filesz: phdr32.p_filesz as elf::Elf64_Xword,
362*bb4ee6a4SAndroid Build Coastguard Worker             p_memsz: phdr32.p_memsz as elf::Elf64_Xword,
363*bb4ee6a4SAndroid Build Coastguard Worker             p_align: phdr32.p_align as elf::Elf64_Xword,
364*bb4ee6a4SAndroid Build Coastguard Worker         }
365*bb4ee6a4SAndroid Build Coastguard Worker     }
366*bb4ee6a4SAndroid Build Coastguard Worker }
367*bb4ee6a4SAndroid Build Coastguard Worker 
368*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
369*bb4ee6a4SAndroid Build Coastguard Worker mod test {
370*bb4ee6a4SAndroid Build Coastguard Worker     use std::fs::File;
371*bb4ee6a4SAndroid Build Coastguard Worker     use std::io::Seek;
372*bb4ee6a4SAndroid Build Coastguard Worker     use std::io::SeekFrom;
373*bb4ee6a4SAndroid Build Coastguard Worker     use std::io::Write;
374*bb4ee6a4SAndroid Build Coastguard Worker 
375*bb4ee6a4SAndroid Build Coastguard Worker     use tempfile::tempfile;
376*bb4ee6a4SAndroid Build Coastguard Worker     use vm_memory::GuestAddress;
377*bb4ee6a4SAndroid Build Coastguard Worker     use vm_memory::GuestMemory;
378*bb4ee6a4SAndroid Build Coastguard Worker 
379*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
380*bb4ee6a4SAndroid Build Coastguard Worker 
381*bb4ee6a4SAndroid Build Coastguard Worker     const MEM_SIZE: u64 = 0x40_0000;
382*bb4ee6a4SAndroid Build Coastguard Worker 
create_guest_mem() -> GuestMemory383*bb4ee6a4SAndroid Build Coastguard Worker     fn create_guest_mem() -> GuestMemory {
384*bb4ee6a4SAndroid Build Coastguard Worker         GuestMemory::new(&[(GuestAddress(0x0), MEM_SIZE)]).unwrap()
385*bb4ee6a4SAndroid Build Coastguard Worker     }
386*bb4ee6a4SAndroid Build Coastguard Worker 
387*bb4ee6a4SAndroid Build Coastguard Worker     // Elf32 image that prints hello world on x86.
make_elf32_bin() -> File388*bb4ee6a4SAndroid Build Coastguard Worker     fn make_elf32_bin() -> File {
389*bb4ee6a4SAndroid Build Coastguard Worker         // test_elf32.bin built on Linux with gcc -m32 -static-pie
390*bb4ee6a4SAndroid Build Coastguard Worker         let bytes = include_bytes!("test_elf32.bin");
391*bb4ee6a4SAndroid Build Coastguard Worker         make_elf_bin(bytes)
392*bb4ee6a4SAndroid Build Coastguard Worker     }
393*bb4ee6a4SAndroid Build Coastguard Worker 
394*bb4ee6a4SAndroid Build Coastguard Worker     // Elf64 image that prints hello world on x86_64.
make_elf64_bin() -> File395*bb4ee6a4SAndroid Build Coastguard Worker     fn make_elf64_bin() -> File {
396*bb4ee6a4SAndroid Build Coastguard Worker         let bytes = include_bytes!("test_elf64.bin");
397*bb4ee6a4SAndroid Build Coastguard Worker         make_elf_bin(bytes)
398*bb4ee6a4SAndroid Build Coastguard Worker     }
399*bb4ee6a4SAndroid Build Coastguard Worker 
make_elf_bin(elf_bytes: &[u8]) -> File400*bb4ee6a4SAndroid Build Coastguard Worker     fn make_elf_bin(elf_bytes: &[u8]) -> File {
401*bb4ee6a4SAndroid Build Coastguard Worker         let mut file = tempfile().expect("failed to create tempfile");
402*bb4ee6a4SAndroid Build Coastguard Worker         file.write_all(elf_bytes)
403*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to write elf to shared memory");
404*bb4ee6a4SAndroid Build Coastguard Worker         file
405*bb4ee6a4SAndroid Build Coastguard Worker     }
406*bb4ee6a4SAndroid Build Coastguard Worker 
mutate_elf_bin(mut f: &File, offset: u64, val: u8)407*bb4ee6a4SAndroid Build Coastguard Worker     fn mutate_elf_bin(mut f: &File, offset: u64, val: u8) {
408*bb4ee6a4SAndroid Build Coastguard Worker         f.seek(SeekFrom::Start(offset))
409*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to seek file");
410*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(&[val])
411*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to write mutated value to file");
412*bb4ee6a4SAndroid Build Coastguard Worker     }
413*bb4ee6a4SAndroid Build Coastguard Worker 
414*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
load_elf32()415*bb4ee6a4SAndroid Build Coastguard Worker     fn load_elf32() {
416*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
417*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(0x0);
418*bb4ee6a4SAndroid Build Coastguard Worker         let mut image = make_elf32_bin();
419*bb4ee6a4SAndroid Build Coastguard Worker         let kernel = load_elf(&gm, kernel_addr, &mut image, 0).unwrap();
420*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.address_range.start, 0);
421*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.address_range.end, 0xa_2038);
422*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.size, 0xa_2038);
423*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.entry, GuestAddress(0x3dc0));
424*bb4ee6a4SAndroid Build Coastguard Worker     }
425*bb4ee6a4SAndroid Build Coastguard Worker 
426*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
load_elf64()427*bb4ee6a4SAndroid Build Coastguard Worker     fn load_elf64() {
428*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
429*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(0x0);
430*bb4ee6a4SAndroid Build Coastguard Worker         let mut image = make_elf64_bin();
431*bb4ee6a4SAndroid Build Coastguard Worker         let kernel = load_elf(&gm, kernel_addr, &mut image, 0).expect("failed to load ELF");
432*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.address_range.start, 0x20_0000);
433*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.address_range.end, 0x20_0035);
434*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.size, 0x35);
435*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(kernel.entry, GuestAddress(0x20_000e));
436*bb4ee6a4SAndroid Build Coastguard Worker     }
437*bb4ee6a4SAndroid Build Coastguard Worker 
438*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
bad_magic()439*bb4ee6a4SAndroid Build Coastguard Worker     fn bad_magic() {
440*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
441*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(0x0);
442*bb4ee6a4SAndroid Build Coastguard Worker         let mut bad_image = make_elf64_bin();
443*bb4ee6a4SAndroid Build Coastguard Worker         mutate_elf_bin(&bad_image, 0x1, 0x33);
444*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
445*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::InvalidMagicNumber),
446*bb4ee6a4SAndroid Build Coastguard Worker             load_elf(&gm, kernel_addr, &mut bad_image, 0)
447*bb4ee6a4SAndroid Build Coastguard Worker         );
448*bb4ee6a4SAndroid Build Coastguard Worker     }
449*bb4ee6a4SAndroid Build Coastguard Worker 
450*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
bad_endian()451*bb4ee6a4SAndroid Build Coastguard Worker     fn bad_endian() {
452*bb4ee6a4SAndroid Build Coastguard Worker         // Only little endian is supported
453*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
454*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(0x20_0000);
455*bb4ee6a4SAndroid Build Coastguard Worker         let mut bad_image = make_elf64_bin();
456*bb4ee6a4SAndroid Build Coastguard Worker         mutate_elf_bin(&bad_image, 0x5, 2);
457*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
458*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::BigEndianOnLittle),
459*bb4ee6a4SAndroid Build Coastguard Worker             load_elf(&gm, kernel_addr, &mut bad_image, 0)
460*bb4ee6a4SAndroid Build Coastguard Worker         );
461*bb4ee6a4SAndroid Build Coastguard Worker     }
462*bb4ee6a4SAndroid Build Coastguard Worker 
463*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
bad_phoff()464*bb4ee6a4SAndroid Build Coastguard Worker     fn bad_phoff() {
465*bb4ee6a4SAndroid Build Coastguard Worker         // program header has to be past the end of the elf header
466*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
467*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(0x0);
468*bb4ee6a4SAndroid Build Coastguard Worker         let mut bad_image = make_elf64_bin();
469*bb4ee6a4SAndroid Build Coastguard Worker         mutate_elf_bin(&bad_image, 0x20, 0x10);
470*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
471*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::InvalidProgramHeaderOffset),
472*bb4ee6a4SAndroid Build Coastguard Worker             load_elf(&gm, kernel_addr, &mut bad_image, 0)
473*bb4ee6a4SAndroid Build Coastguard Worker         );
474*bb4ee6a4SAndroid Build Coastguard Worker     }
475*bb4ee6a4SAndroid Build Coastguard Worker 
476*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
paddr_below_start()477*bb4ee6a4SAndroid Build Coastguard Worker     fn paddr_below_start() {
478*bb4ee6a4SAndroid Build Coastguard Worker         let gm = create_guest_mem();
479*bb4ee6a4SAndroid Build Coastguard Worker         // test_elf.bin loads a phdr at 0x20_0000, so this will fail due to an out-of-bounds address
480*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_addr = GuestAddress(0x30_0000);
481*bb4ee6a4SAndroid Build Coastguard Worker         let mut image = make_elf64_bin();
482*bb4ee6a4SAndroid Build Coastguard Worker         let res = load_elf(&gm, kernel_addr, &mut image, 0);
483*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(res, Err(Error::ProgramHeaderAddressOutOfRange));
484*bb4ee6a4SAndroid Build Coastguard Worker     }
485*bb4ee6a4SAndroid Build Coastguard Worker }
486