roxy_loader/
elf_processing.rs1use anyhow::{Context, Result, bail};
2use elfloader::ElfBinary;
3
4pub fn parse_kernel_elf(kernel_file: &[u8]) -> Result<ElfBinary<'_>> {
5 ElfBinary::new(kernel_file)
6 .ok()
7 .context("Failed to parse kernel elf")
8}
9
10pub fn validate_kernel_elf(kernel_elf: &ElfBinary<'_>) -> Result<()> {
11 if kernel_elf.is_pie() {
12 bail!("PIE kernels are not supported.");
13 }
14
15 Ok(())
16}
17
18pub fn kernel_entry_point(kernel_elf: &ElfBinary<'_>) -> u64 {
19 kernel_elf.entry_point()
20}
21
22#[cfg(test)]
23mod tests {
24 use alloc::{string::ToString, vec, vec::Vec};
25
26 use super::{kernel_entry_point, parse_kernel_elf, validate_kernel_elf};
27
28 const ELF64_HEADER_SIZE: usize = 64;
29 const PROGRAM_HEADER_SIZE: usize = 56;
30 const PT_DYNAMIC: u32 = 2;
31 const DT_NULL: i64 = 0;
32 const DT_FLAGS_1: i64 = 0x6ffffffb;
33 const DF_1_PIE: u64 = 0x0800_0000;
34
35 #[test]
36 fn parse_kernel_elf_rejects_non_elf_bytes() {
37 let error = parse_kernel_elf(b"definitely-not-an-elf").unwrap_err();
38 assert_eq!(error.to_string(), "Failed to parse kernel elf");
39 }
40
41 #[test]
42 fn validate_kernel_elf_rejects_pie_binaries() {
43 let bytes = pie_elf_bytes(0x401000);
44 let elf = parse_kernel_elf(&bytes).unwrap();
45 let error = validate_kernel_elf(&elf).unwrap_err();
46 assert_eq!(error.to_string(), "PIE kernels are not supported.");
47 }
48
49 #[test]
50 fn kernel_entry_point_returns_elf_entry_address() {
51 let bytes = executable_elf_bytes(0x401000);
52 let elf = parse_kernel_elf(&bytes).unwrap();
53
54 validate_kernel_elf(&elf).unwrap();
55 assert_eq!(kernel_entry_point(&elf), 0x401000);
56 }
57
58 fn executable_elf_bytes(entry_point: u64) -> Vec<u8> {
59 let mut bytes = vec![0_u8; ELF64_HEADER_SIZE];
60 write_elf_header(&mut bytes, entry_point, 0, 0);
61 bytes
62 }
63
64 fn pie_elf_bytes(entry_point: u64) -> Vec<u8> {
65 let phoff = ELF64_HEADER_SIZE as u64;
66 let dyn_offset = (ELF64_HEADER_SIZE + PROGRAM_HEADER_SIZE) as u64;
67 let dyn_size = 32_u64;
68
69 let mut bytes = vec![0_u8; dyn_offset as usize + dyn_size as usize];
70 write_elf_header(&mut bytes, entry_point, phoff, 1);
71 write_program_header(
72 &mut bytes[ELF64_HEADER_SIZE..ELF64_HEADER_SIZE + PROGRAM_HEADER_SIZE],
73 dyn_offset,
74 dyn_size,
75 );
76 write_dynamic_entry(
77 &mut bytes[dyn_offset as usize..dyn_offset as usize + 16],
78 DT_FLAGS_1,
79 DF_1_PIE,
80 );
81 write_dynamic_entry(
82 &mut bytes[dyn_offset as usize + 16..dyn_offset as usize + 32],
83 DT_NULL,
84 0,
85 );
86 bytes
87 }
88
89 fn write_elf_header(bytes: &mut [u8], entry_point: u64, phoff: u64, phnum: u16) {
90 bytes[..4].copy_from_slice(b"\x7FELF");
91 bytes[4] = 2;
92 bytes[5] = 1;
93 bytes[6] = 1;
94 bytes[7] = 0;
95 bytes[8..16].fill(0);
96
97 bytes[16..18].copy_from_slice(&2_u16.to_le_bytes());
98 bytes[18..20].copy_from_slice(&0x3e_u16.to_le_bytes());
99 bytes[20..24].copy_from_slice(&1_u32.to_le_bytes());
100 bytes[24..32].copy_from_slice(&entry_point.to_le_bytes());
101 bytes[32..40].copy_from_slice(&phoff.to_le_bytes());
102 bytes[40..48].copy_from_slice(&0_u64.to_le_bytes());
103 bytes[48..52].copy_from_slice(&0_u32.to_le_bytes());
104 bytes[52..54].copy_from_slice(&(ELF64_HEADER_SIZE as u16).to_le_bytes());
105 bytes[54..56].copy_from_slice(&(PROGRAM_HEADER_SIZE as u16).to_le_bytes());
106 bytes[56..58].copy_from_slice(&phnum.to_le_bytes());
107 bytes[58..60].copy_from_slice(&0_u16.to_le_bytes());
108 bytes[60..62].copy_from_slice(&0_u16.to_le_bytes());
109 bytes[62..64].copy_from_slice(&0_u16.to_le_bytes());
110 }
111
112 fn write_program_header(bytes: &mut [u8], offset: u64, size: u64) {
113 bytes[0..4].copy_from_slice(&PT_DYNAMIC.to_le_bytes());
114 bytes[4..8].copy_from_slice(&0_u32.to_le_bytes());
115 bytes[8..16].copy_from_slice(&offset.to_le_bytes());
116 bytes[16..24].copy_from_slice(&0_u64.to_le_bytes());
117 bytes[24..32].copy_from_slice(&0_u64.to_le_bytes());
118 bytes[32..40].copy_from_slice(&size.to_le_bytes());
119 bytes[40..48].copy_from_slice(&size.to_le_bytes());
120 bytes[48..56].copy_from_slice(&8_u64.to_le_bytes());
121 }
122
123 fn write_dynamic_entry(bytes: &mut [u8], tag: i64, value: u64) {
124 bytes[0..8].copy_from_slice(&tag.to_le_bytes());
125 bytes[8..16].copy_from_slice(&value.to_le_bytes());
126 }
127}