Skip to main content

sbpf_disassembler/
elf_header.rs

1use {
2    crate::errors::DisassemblerError,
3    object::{Endianness, read::elf::ElfFile64},
4    serde::{Deserialize, Serialize, Serializer},
5    std::str,
6};
7
8pub const EI_MAGIC: [u8; 4] = *b"\x7fELF"; // ELF magic
9pub const EI_CLASS: u8 = 0x02; // 64-bit
10pub const EI_DATA: u8 = 0x01; // Little endian
11pub const EI_VERSION: u8 = 0x01; // Version 1
12pub const EI_OSABI: u8 = 0x00; // System V
13pub const EI_ABIVERSION: u8 = 0x00; // No ABI version
14pub const EI_PAD: [u8; 7] = [0u8; 7]; // Padding
15pub const E_TYPE: u16 = 0x03; // ET_DYN - shared object
16pub const E_MACHINE: u16 = 0xf7; // Berkeley Packet Filter
17pub const E_MACHINE_SBPF: u16 = 0x0107; // Solana Berkeley Packet Filter
18pub const E_VERSION: u32 = 0x01; // Original version of BPF
19
20fn elf_magic<S>(magic: &[u8; 4], serializer: S) -> Result<S::Ok, S::Error>
21where
22    S: Serializer,
23{
24    let s = String::from_utf8_lossy(magic);
25    serializer.serialize_str(&s)
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct ELFHeader {
30    #[serde(serialize_with = "elf_magic")]
31    pub ei_magic: [u8; 4],
32    pub ei_class: u8,
33    pub ei_data: u8,
34    pub ei_version: u8,
35    pub ei_osabi: u8,
36    pub ei_abiversion: u8,
37    pub ei_pad: [u8; 7],
38    pub e_type: u16,
39    pub e_machine: u16,
40    pub e_version: u32,
41    pub e_entry: u64,
42    pub e_phoff: u64,
43    pub e_shoff: u64,
44    pub e_flags: u32,
45    pub e_ehsize: u16,
46    pub e_phentsize: u16,
47    pub e_phnum: u16,
48    pub e_shentsize: u16,
49    pub e_shnum: u16,
50    pub e_shstrndx: u16,
51}
52
53impl ELFHeader {
54    pub fn from_elf_file(elf_file: &ElfFile64<Endianness>) -> Result<Self, DisassemblerError> {
55        let endian = elf_file.endian();
56        let elf_header = elf_file.elf_header();
57
58        // Extract ELF header fields.
59        let e_ident = elf_header.e_ident;
60        let e_type = elf_header.e_type.get(endian);
61        let e_machine = elf_header.e_machine.get(endian);
62        let e_version = elf_header.e_version.get(endian);
63        let e_entry = elf_header.e_entry.get(endian);
64        let e_phoff = elf_header.e_phoff.get(endian);
65        let e_shoff = elf_header.e_shoff.get(endian);
66        let e_flags = elf_header.e_flags.get(endian);
67        let e_ehsize = elf_header.e_ehsize.get(endian);
68        let e_phentsize = elf_header.e_phentsize.get(endian);
69        let e_phnum = elf_header.e_phnum.get(endian);
70        let e_shentsize = elf_header.e_shentsize.get(endian);
71        let e_shnum = elf_header.e_shnum.get(endian);
72        let e_shstrndx = elf_header.e_shstrndx.get(endian);
73
74        // Validate ELF header fields.
75        if e_ident.magic.ne(&EI_MAGIC)
76            || e_ident.class.ne(&EI_CLASS)
77            || e_ident.data.ne(&EI_DATA)
78            || e_ident.version.ne(&EI_VERSION)
79            || e_ident.os_abi.ne(&EI_OSABI)
80            || e_ident.abi_version.ne(&EI_ABIVERSION)
81            || e_ident.padding.ne(&EI_PAD)
82            || (e_machine.ne(&E_MACHINE) && e_machine.ne(&E_MACHINE_SBPF))
83            || e_version.ne(&E_VERSION)
84        {
85            return Err(DisassemblerError::NonStandardElfHeader);
86        }
87
88        Ok(ELFHeader {
89            ei_magic: e_ident.magic,
90            ei_class: e_ident.class,
91            ei_data: e_ident.data,
92            ei_version: e_ident.version,
93            ei_osabi: e_ident.os_abi,
94            ei_abiversion: e_ident.abi_version,
95            ei_pad: e_ident.padding,
96            e_type,
97            e_machine,
98            e_version,
99            e_entry,
100            e_phoff,
101            e_shoff,
102            e_flags,
103            e_ehsize,
104            e_phentsize,
105            e_phnum,
106            e_shentsize,
107            e_shnum,
108            e_shstrndx,
109        })
110    }
111
112    pub fn to_bytes(&self) -> Vec<u8> {
113        let mut b = self.ei_magic.to_vec();
114        b.extend_from_slice(&[
115            self.ei_class,
116            self.ei_data,
117            self.ei_version,
118            self.ei_osabi,
119            self.ei_abiversion,
120        ]);
121        b.extend_from_slice(&self.ei_pad);
122        b.extend_from_slice(&self.e_type.to_le_bytes());
123        b.extend_from_slice(&self.e_machine.to_le_bytes());
124        b.extend_from_slice(&self.e_version.to_le_bytes());
125        b.extend_from_slice(&self.e_entry.to_le_bytes());
126        b.extend_from_slice(&self.e_phoff.to_le_bytes());
127        b.extend_from_slice(&self.e_shoff.to_le_bytes());
128        b.extend_from_slice(&self.e_flags.to_le_bytes());
129        b.extend_from_slice(&self.e_ehsize.to_le_bytes());
130        b.extend_from_slice(&self.e_phentsize.to_le_bytes());
131        b.extend_from_slice(&self.e_phnum.to_le_bytes());
132        b.extend_from_slice(&self.e_shentsize.to_le_bytes());
133        b.extend_from_slice(&self.e_shnum.to_le_bytes());
134        b.extend_from_slice(&self.e_shstrndx.to_le_bytes());
135        b
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use {
142        super::*,
143        crate::{
144            elf_header::{
145                E_MACHINE, E_MACHINE_SBPF, E_TYPE, E_VERSION, EI_ABIVERSION, EI_CLASS, EI_DATA,
146                EI_MAGIC, EI_OSABI, EI_PAD, EI_VERSION,
147            },
148            program::Program,
149        },
150        hex_literal::hex,
151    };
152
153    #[test]
154    fn test_elf_header() {
155        let program = Program::from_bytes(&hex!("7F454C460201010000000000000000000300F700010000002001000000000000400000000000000028020000000000000000000040003800030040000600050001000000050000002001000000000000200100000000000020010000000000003000000000000000300000000000000000100000000000000100000004000000C001000000000000C001000000000000C0010000000000003C000000000000003C000000000000000010000000000000020000000600000050010000000000005001000000000000500100000000000070000000000000007000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007912A000000000007911182900000000B7000000010000002D21010000000000B70000000000000095000000000000001E0000000000000004000000000000000600000000000000C0010000000000000B0000000000000018000000000000000500000000000000F0010000000000000A000000000000000C00000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000120001002001000000000000300000000000000000656E747279706F696E7400002E74657874002E64796E737472002E64796E73796D002E64796E616D6963002E73687374727461620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000010000000600000000000000200100000000000020010000000000003000000000000000000000000000000008000000000000000000000000000000170000000600000003000000000000005001000000000000500100000000000070000000000000000400000000000000080000000000000010000000000000000F0000000B0000000200000000000000C001000000000000C001000000000000300000000000000004000000010000000800000000000000180000000000000007000000030000000200000000000000F001000000000000F0010000000000000C00000000000000000000000000000001000000000000000000000000000000200000000300000000000000000000000000000000000000FC010000000000002A00000000000000000000000000000001000000000000000000000000000000")).unwrap();
156
157        // Verify ELF header fields match expected constants.
158        assert_eq!(program.elf_header.ei_magic, EI_MAGIC);
159        assert_eq!(program.elf_header.ei_class, EI_CLASS);
160        assert_eq!(program.elf_header.ei_data, EI_DATA);
161        assert_eq!(program.elf_header.ei_version, EI_VERSION);
162        assert_eq!(program.elf_header.ei_osabi, EI_OSABI);
163        assert_eq!(program.elf_header.ei_abiversion, EI_ABIVERSION);
164        assert_eq!(program.elf_header.ei_pad, EI_PAD);
165        assert_eq!(program.elf_header.e_type, E_TYPE);
166        assert!(
167            program.elf_header.e_machine == E_MACHINE_SBPF
168                || program.elf_header.e_machine == E_MACHINE
169        );
170        assert_eq!(program.elf_header.e_version, E_VERSION);
171    }
172
173    #[test]
174    fn test_elf_header_to_bytes() {
175        let header = ELFHeader {
176            ei_magic: EI_MAGIC,
177            ei_class: EI_CLASS,
178            ei_data: EI_DATA,
179            ei_version: EI_VERSION,
180            ei_osabi: EI_OSABI,
181            ei_abiversion: EI_ABIVERSION,
182            ei_pad: EI_PAD,
183            e_type: 0x03,
184            e_machine: 0xf7,
185            e_version: 0x01,
186            e_entry: 0x120,
187            e_phoff: 64,
188            e_shoff: 552,
189            e_flags: 0,
190            e_ehsize: 64,
191            e_phentsize: 56,
192            e_phnum: 3,
193            e_shentsize: 64,
194            e_shnum: 6,
195            e_shstrndx: 5,
196        };
197
198        let bytes = header.to_bytes();
199        assert_eq!(bytes.len(), 64);
200        assert_eq!(&bytes[0..4], &EI_MAGIC);
201        assert_eq!(bytes[4], EI_CLASS);
202        assert_eq!(bytes[5], EI_DATA);
203        assert_eq!(bytes[6], EI_VERSION);
204        assert_eq!(bytes[7], EI_OSABI);
205        assert_eq!(bytes[8], EI_ABIVERSION);
206        assert_eq!(&bytes[9..16], &EI_PAD);
207    }
208
209    #[test]
210    fn test_elf_header_validation_errors() {
211        // Test invalid ELF headers
212
213        // Invalid magic.
214        let invalid_magic = hex!(
215            "00454C460201010000000000000000000300F700010000000000000000000000400000000000000000000000000000000000000040003800000000000000000000"
216        );
217        let result = Program::from_bytes(&invalid_magic);
218        assert!(result.is_err());
219
220        // Invalid class (not 64-bit).
221        let invalid_class = hex!(
222            "7F454C460101010000000000000000000300F700010000000000000000000000400000000000000000000000000000000000000040003800000000000000000000"
223        );
224        let result = Program::from_bytes(&invalid_class);
225        assert!(result.is_err());
226
227        // Invalid endianness (big endian instead of little).
228        let invalid_endian = hex!(
229            "7F454C460202010000000000000000000300F700010000000000000000000000400000000000000000000000000000000000000040003800000000000000000000"
230        );
231        let result = Program::from_bytes(&invalid_endian);
232        assert!(result.is_err());
233    }
234}