Skip to main content

roxy_loader/
elf_processing.rs

1use 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}