Parse an ELF-64 image from raw bytes # Returns Parsed ELF structure or error if the format is invalid
(bytes: &[u8])
| 27 | const ELF_MAGIC: &[u8; 4] = b"\x7fELF"; |
| 28 | const ELFCLASS64: u8 = 2; |
| 29 | const ELFDATA2LSB: u8 = 1; |
| 30 | const PT_LOAD: u32 = 1; |
| 31 | |
| 32 | if bytes.len() < 64 { |
| 33 | return Err(VmError::Other("ELF image is too small".to_owned())); |
| 34 | } |
| 35 | if &bytes[0..4] != ELF_MAGIC { |
| 36 | return Err(VmError::Other("ELF magic header missing".to_owned())); |
| 37 | } |
| 38 | if bytes[4] != ELFCLASS64 { |
| 39 | return Err(VmError::Other("ELF image is not 64-bit".to_owned())); |
| 40 | } |
| 41 | if bytes[5] != ELFDATA2LSB { |
| 42 | return Err(VmError::Other("ELF image is not little-endian".to_owned())); |
| 43 | } |
| 44 | |
| 45 | let entry_point = read_u64(bytes, 24)?; |
| 46 | let phoff = read_u64(bytes, 32)?; |
| 47 | let phentsize = read_u16(bytes, 54)? as u64; |
| 48 | let phnum = read_u16(bytes, 56)? as u64; |
| 49 | |
| 50 | if phentsize < 56 { |
| 51 | return Err(VmError::Other( |
| 52 | "ELF program header size is invalid".to_owned(), |
| 53 | )); |
| 54 | } |
| 55 | |
| 56 | let mut load_segments = Vec::new(); |
| 57 | for i in 0..phnum { |
| 58 | let base = phoff |
| 59 | .checked_add(i * phentsize) |
| 60 | .ok_or_else(|| VmError::Other("ELF program header overflow".to_owned()))?; |
| 61 | let ph = base as usize; |
| 62 | let end = ph |
| 63 | .checked_add(phentsize as usize) |
| 64 | .ok_or_else(|| VmError::Other("ELF program header slice overflow".to_owned()))?; |
| 65 | let header = bytes |
| 66 | .get(ph..end) |
| 67 | .ok_or_else(|| VmError::Other("ELF program header outside file".to_owned()))?; |
| 68 | |
| 69 | let p_type = read_u32(header, 0)?; |
| 70 | if p_type != PT_LOAD { |
| 71 | continue; |
| 72 | } |
| 73 | |
| 74 | load_segments.push(ElfLoadSegment { |
| 75 | offset: read_u64(header, 8)?, |
| 76 | vaddr: read_u64(header, 16)?, |
| 77 | file_size: read_u64(header, 32)?, |
| 78 | mem_size: read_u64(header, 40)?, |
| 79 | }); |
| 80 | } |
| 81 | |
| 82 | if load_segments.is_empty() { |
| 83 | return Err(VmError::Other( |
| 84 | "ELF contains no PT_LOAD segments".to_owned(), |
| 85 | )); |
| 86 | } |
no test coverage detected