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