1use crate::abi;
3use crate::endian::EndianParse;
4use crate::parse::ParseError;
5
6#[derive(Debug, Copy, Clone, PartialEq, Eq)]
8pub enum Class {
9 ELF32,
10 ELF64,
11}
12
13#[derive(Debug)]
17#[repr(C)]
18pub struct Elf32_Ehdr {
19 pub e_ident: [u8; abi::EI_NIDENT],
20 pub e_type: u16,
21 pub e_machine: u16,
22 pub e_version: u32,
23 pub e_entry: u32,
24 pub e_phoff: u32,
25 pub e_shoff: u32,
26 pub e_flags: u32,
27 pub e_ehsize: u16,
28 pub e_phentsize: u16,
29 pub e_phnum: u16,
30 pub e_shentsize: u16,
31 pub e_shnum: u16,
32 pub e_shstrndx: u16,
33}
34
35#[derive(Debug)]
39#[repr(C)]
40pub struct Elf64_Ehdr {
41 pub e_ident: [u8; abi::EI_NIDENT],
42 pub e_type: u16,
43 pub e_machine: u16,
44 pub e_version: u32,
45 pub e_entry: u64,
46 pub e_phoff: u64,
47 pub e_shoff: u64,
48 pub e_flags: u32,
49 pub e_ehsize: u16,
50 pub e_phentsize: u16,
51 pub e_phnum: u16,
52 pub e_shentsize: u16,
53 pub e_shnum: u16,
54 pub e_shstrndx: u16,
55}
56
57#[derive(Copy, Clone, Debug, PartialEq, Eq)]
64pub struct FileHeader<E: EndianParse> {
65 pub class: Class,
67 pub endianness: E,
69 pub version: u32,
71 pub osabi: u8,
73 pub abiversion: u8,
75 pub e_type: u16,
77 pub e_machine: u16,
79 pub e_entry: u64,
87 pub e_phoff: u64,
90 pub e_shoff: u64,
93 pub e_flags: u32,
95 pub e_ehsize: u16,
97 pub e_phentsize: u16,
99 pub e_phnum: u16,
102 pub e_shentsize: u16,
105 pub e_shnum: u16,
112 pub e_shstrndx: u16,
119}
120
121pub const ELF32_EHDR_TAILSIZE: usize = 36;
122pub const ELF64_EHDR_TAILSIZE: usize = 48;
123
124fn verify_ident(buf: &[u8]) -> Result<(), ParseError> {
125 let magic = buf.split_at(abi::EI_CLASS).0;
127 if magic != abi::ELFMAGIC {
128 return Err(ParseError::BadMagic([
129 magic[0], magic[1], magic[2], magic[3],
130 ]));
131 }
132
133 let version = buf[abi::EI_VERSION];
135 if version != abi::EV_CURRENT {
136 return Err(ParseError::UnsupportedVersion((
137 version as u64,
138 abi::EV_CURRENT as u64,
139 )));
140 }
141
142 Ok(())
143}
144
145pub fn parse_ident<E: EndianParse>(data: &[u8]) -> Result<(E, Class, u8, u8), ParseError> {
146 verify_ident(data)?;
147
148 let e_class = data[abi::EI_CLASS];
149 let class = match e_class {
150 abi::ELFCLASS32 => Class::ELF32,
151 abi::ELFCLASS64 => Class::ELF64,
152 _ => {
153 return Err(ParseError::UnsupportedElfClass(e_class));
154 }
155 };
156
157 let file_endian = E::from_ei_data(data[abi::EI_DATA])?;
159
160 Ok((
161 file_endian,
162 class,
163 data[abi::EI_OSABI],
164 data[abi::EI_ABIVERSION],
165 ))
166}
167
168impl<E: EndianParse> FileHeader<E> {
169 pub fn parse_tail(ident: (E, Class, u8, u8), data: &[u8]) -> Result<FileHeader<E>, ParseError> {
170 let (file_endian, class, osabi, abiversion) = ident;
171
172 let mut offset = 0;
173 let e_type = file_endian.parse_u16_at(&mut offset, data)?;
174 let e_machine = file_endian.parse_u16_at(&mut offset, data)?;
175 let version = file_endian.parse_u32_at(&mut offset, data)?;
176
177 let e_entry: u64;
178 let e_phoff: u64;
179 let e_shoff: u64;
180
181 if class == Class::ELF32 {
182 e_entry = file_endian.parse_u32_at(&mut offset, data)? as u64;
183 e_phoff = file_endian.parse_u32_at(&mut offset, data)? as u64;
184 e_shoff = file_endian.parse_u32_at(&mut offset, data)? as u64;
185 } else {
186 e_entry = file_endian.parse_u64_at(&mut offset, data)?;
187 e_phoff = file_endian.parse_u64_at(&mut offset, data)?;
188 e_shoff = file_endian.parse_u64_at(&mut offset, data)?;
189 }
190
191 let e_flags = file_endian.parse_u32_at(&mut offset, data)?;
192 let e_ehsize = file_endian.parse_u16_at(&mut offset, data)?;
193 let e_phentsize = file_endian.parse_u16_at(&mut offset, data)?;
194 let e_phnum = file_endian.parse_u16_at(&mut offset, data)?;
195 let e_shentsize = file_endian.parse_u16_at(&mut offset, data)?;
196 let e_shnum = file_endian.parse_u16_at(&mut offset, data)?;
197 let e_shstrndx = file_endian.parse_u16_at(&mut offset, data)?;
198
199 Ok(FileHeader {
200 class,
201 endianness: file_endian,
202 version,
203 e_type,
204 e_machine,
205 osabi,
206 abiversion,
207 e_entry,
208 e_phoff,
209 e_shoff,
210 e_flags,
211 e_ehsize,
212 e_phentsize,
213 e_phnum,
214 e_shentsize,
215 e_shnum,
216 e_shstrndx,
217 })
218 }
219}
220
221#[cfg(test)]
222mod parse_tests {
223 use super::*;
224 use crate::endian::AnyEndian;
225
226 #[test]
227 fn test_verify_ident_valid() {
228 let data: [u8; abi::EI_NIDENT] = [
229 abi::ELFMAG0,
230 abi::ELFMAG1,
231 abi::ELFMAG2,
232 abi::ELFMAG3,
233 abi::ELFCLASS32,
234 abi::ELFDATA2LSB,
235 abi::EV_CURRENT,
236 abi::ELFOSABI_LINUX,
237 0,
238 0,
239 0,
240 0,
241 0,
242 0,
243 0,
244 0,
245 ];
246 verify_ident(data.as_ref()).expect("Expected Ok result");
247 }
248
249 #[test]
250 fn test_verify_ident_invalid_mag0() {
251 let data: [u8; abi::EI_NIDENT] = [
252 0xFF,
253 abi::ELFMAG1,
254 abi::ELFMAG2,
255 abi::ELFMAG3,
256 abi::ELFCLASS32,
257 abi::ELFDATA2LSB,
258 abi::EV_CURRENT,
259 abi::ELFOSABI_LINUX,
260 0,
261 0,
262 0,
263 0,
264 0,
265 0,
266 0,
267 0,
268 ];
269 let result = verify_ident(data.as_ref()).expect_err("Expected an error");
270 assert!(
271 matches!(result, ParseError::BadMagic(_)),
272 "Unexpected Error type found: {result}"
273 );
274 }
275
276 #[test]
277 fn test_verify_ident_invalid_mag1() {
278 let data: [u8; abi::EI_NIDENT] = [
279 abi::ELFMAG0,
280 0xFF,
281 abi::ELFMAG2,
282 abi::ELFMAG3,
283 abi::ELFCLASS32,
284 abi::ELFDATA2LSB,
285 abi::EV_CURRENT,
286 abi::ELFOSABI_LINUX,
287 0,
288 0,
289 0,
290 0,
291 0,
292 0,
293 0,
294 0,
295 ];
296 let result = verify_ident(data.as_ref()).expect_err("Expected an error");
297 assert!(
298 matches!(result, ParseError::BadMagic(_)),
299 "Unexpected Error type found: {result}"
300 );
301 }
302
303 #[test]
304 fn test_verify_ident_invalid_mag2() {
305 let data: [u8; abi::EI_NIDENT] = [
306 abi::ELFMAG0,
307 abi::ELFMAG1,
308 0xFF,
309 abi::ELFMAG3,
310 abi::ELFCLASS32,
311 abi::ELFDATA2LSB,
312 abi::EV_CURRENT,
313 abi::ELFOSABI_LINUX,
314 0,
315 0,
316 0,
317 0,
318 0,
319 0,
320 0,
321 0,
322 ];
323 let result = verify_ident(data.as_ref()).expect_err("Expected an error");
324 assert!(
325 matches!(result, ParseError::BadMagic(_)),
326 "Unexpected Error type found: {result}"
327 );
328 }
329
330 #[test]
331 fn test_verify_ident_invalid_mag3() {
332 let data: [u8; abi::EI_NIDENT] = [
333 abi::ELFMAG0,
334 abi::ELFMAG1,
335 abi::ELFMAG2,
336 0xFF,
337 abi::ELFCLASS32,
338 abi::ELFDATA2LSB,
339 abi::EV_CURRENT,
340 abi::ELFOSABI_LINUX,
341 0,
342 0,
343 0,
344 0,
345 0,
346 0,
347 0,
348 0,
349 ];
350 let result = verify_ident(data.as_ref()).expect_err("Expected an error");
351 assert!(
352 matches!(result, ParseError::BadMagic(_)),
353 "Unexpected Error type found: {result}"
354 );
355 }
356
357 #[allow(deprecated)]
358 #[test]
359 fn test_verify_ident_invalid_version() {
360 let data: [u8; abi::EI_NIDENT] = [
361 abi::ELFMAG0,
362 abi::ELFMAG1,
363 abi::ELFMAG2,
364 abi::ELFMAG3,
365 abi::ELFCLASS32,
366 abi::ELFDATA2LSB,
367 42,
368 abi::ELFOSABI_LINUX,
369 0,
370 0,
371 0,
372 0,
373 0,
374 0,
375 0,
376 0,
377 ];
378 let result = verify_ident(data.as_ref()).expect_err("Expected an error");
379 assert!(
380 matches!(result, ParseError::UnsupportedVersion((42, 1))),
381 "Unexpected Error type found: {result}"
382 );
383 }
384
385 #[test]
386 fn test_parse_ehdr32_works() {
387 let ident = (AnyEndian::Little, Class::ELF32, abi::ELFOSABI_LINUX, 7u8);
388 let mut tail = [0u8; ELF64_EHDR_TAILSIZE];
389 for (n, elem) in tail.iter_mut().enumerate().take(ELF64_EHDR_TAILSIZE) {
390 *elem = n as u8;
391 }
392
393 assert_eq!(
394 FileHeader::parse_tail(ident, &tail).unwrap(),
395 FileHeader {
396 class: Class::ELF32,
397 endianness: AnyEndian::Little,
398 version: 0x7060504,
399 osabi: abi::ELFOSABI_LINUX,
400 abiversion: 7,
401 e_type: 0x100,
402 e_machine: 0x302,
403 e_entry: 0x0B0A0908,
404 e_phoff: 0x0F0E0D0C,
405 e_shoff: 0x13121110,
406 e_flags: 0x17161514,
407 e_ehsize: 0x1918,
408 e_phentsize: 0x1B1A,
409 e_phnum: 0x1D1C,
410 e_shentsize: 0x1F1E,
411 e_shnum: 0x2120,
412 e_shstrndx: 0x2322,
413 }
414 );
415 }
416
417 #[test]
418 fn test_parse_ehdr32_fuzz_too_short() {
419 let ident = (AnyEndian::Little, Class::ELF32, abi::ELFOSABI_LINUX, 7u8);
420 let tail = [0u8; ELF32_EHDR_TAILSIZE];
421
422 for n in 0..ELF32_EHDR_TAILSIZE {
423 let buf = tail.split_at(n).0;
424 let result = FileHeader::parse_tail(ident, buf).expect_err("Expected an error");
425 assert!(
426 matches!(result, ParseError::SliceReadError(_)),
427 "Unexpected Error type found: {result:?}"
428 );
429 }
430 }
431
432 #[test]
433 fn test_parse_ehdr64_works() {
434 let ident = (AnyEndian::Big, Class::ELF64, abi::ELFOSABI_LINUX, 7u8);
435 let mut tail = [0u8; ELF64_EHDR_TAILSIZE];
436 for (n, elem) in tail.iter_mut().enumerate().take(ELF64_EHDR_TAILSIZE) {
437 *elem = n as u8;
438 }
439
440 assert_eq!(
441 FileHeader::parse_tail(ident, &tail).unwrap(),
442 FileHeader {
443 class: Class::ELF64,
444 endianness: AnyEndian::Big,
445 version: 0x04050607,
446 osabi: abi::ELFOSABI_LINUX,
447 abiversion: 7,
448 e_type: 0x0001,
449 e_machine: 0x0203,
450 e_entry: 0x08090A0B0C0D0E0F,
451 e_phoff: 0x1011121314151617,
452 e_shoff: 0x18191A1B1C1D1E1F,
453 e_flags: 0x20212223,
454 e_ehsize: 0x2425,
455 e_phentsize: 0x2627,
456 e_phnum: 0x2829,
457 e_shentsize: 0x2A2B,
458 e_shnum: 0x2C2D,
459 e_shstrndx: 0x2E2F,
460 }
461 );
462 }
463
464 #[test]
465 fn test_parse_ehdr64_fuzz_too_short() {
466 let ident = (AnyEndian::Little, Class::ELF64, abi::ELFOSABI_LINUX, 7u8);
467 let tail = [0u8; ELF64_EHDR_TAILSIZE];
468
469 for n in 0..ELF64_EHDR_TAILSIZE {
470 let buf = tail.split_at(n).0;
471 let result = FileHeader::parse_tail(ident, buf).expect_err("Expected an error");
472 assert!(
473 matches!(result, ParseError::SliceReadError(_)),
474 "Unexpected Error type found: {result:?}"
475 );
476 }
477 }
478}