• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
3  * Licensed under the Mulan PSL v2.
4  * You can use this software according to the terms and conditions of the Mulan PSL v2.
5  * You may obtain a copy of Mulan PSL v2 at:
6  *     http://license.coscl.org.cn/MulanPSL2
7  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8  * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9  * PURPOSE.
10  * See the Mulan PSL v2 for more details.
11  */
12 #define _GNU_SOURCE
13 
14 #include <malloc.h>
15 #include <errno.h>
16 #include <endian.h>
17 #include <stdbool.h>
18 #include "elf.h"
19 
20 #define PAGE_SIZE 0x1000
21 
is_elf_magic(struct elf_indent * indent)22 static bool is_elf_magic(struct elf_indent *indent)
23 {
24     return (indent->ei_magic[0] == 0x7F && indent->ei_magic[1] == 'E'
25             && indent->ei_magic[2] == 'L' && indent->ei_magic[3] == 'F');
26 }
27 
28 #define ELF_ENDIAN_LE(indent) ((indent).ei_data == 1)
29 #define ELF_ENDIAN_BE(indent) ((indent).ei_data == 2)
30 
31 #define ELF_BITS_32(indent) ((indent).ei_class == 1)
32 #define ELF_BITS_64(indent) ((indent).ei_class == 2)
33 
34 /**
35  * Parse an ELF file header. We use the 64-bit structure `struct elf_header` as
36  * the output structure.
37  *
38  * On error, the negative error code is returned.
39  * On success, 0 is returned, and the header is written in the given parameter.
40  */
parse_elf_header(const char * code,struct elf_header * header)41 static int parse_elf_header(const char *code, struct elf_header *header)
42 {
43     struct elf_header *header_64 = (struct elf_header *)code;
44     struct elf_header_32 *header_32 = (struct elf_header_32 *)code;
45 
46     if (!is_elf_magic(&header_64->e_indent)) {
47         return -EINVAL;
48     }
49 
50     header->e_indent = *(struct elf_indent *)code;
51 
52     if (ELF_ENDIAN_LE(header->e_indent)) {
53         /*
54          * For the first few bytes, both 32-bit and 64-bit ELF headers
55          * have the same field width. So, we simply use header_64 at
56          * first.
57          */
58         header->e_type = le16toh(header_64->e_type);
59         header->e_machine = le16toh(header_64->e_machine);
60         header->e_version = le32toh(header_32->e_version);
61         if (ELF_BITS_32(header->e_indent)) {
62             header->e_entry = le32toh(header_32->e_entry);
63             header->e_phoff = le32toh(header_32->e_phoff);
64             header->e_shoff = le32toh(header_32->e_shoff);
65             header->e_flags = le32toh(header_32->e_flags);
66             header->e_ehsize = le16toh(header_32->e_ehsize);
67             header->e_phentsize = le16toh(header_32->e_phentsize);
68             header->e_phnum = le16toh(header_32->e_phnum);
69             header->e_shentsize = le16toh(header_32->e_shentsize);
70             header->e_shnum = le16toh(header_32->e_shnum);
71             header->e_shstrndx = le16toh(header_32->e_shstrndx);
72         } else if (ELF_BITS_64(header->e_indent)) {
73             header->e_entry = le64toh(header_64->e_entry);
74             header->e_phoff = le64toh(header_64->e_phoff);
75             header->e_shoff = le64toh(header_64->e_shoff);
76             header->e_flags = le32toh(header_64->e_flags);
77             header->e_ehsize = le16toh(header_64->e_ehsize);
78             header->e_phentsize = le16toh(header_64->e_phentsize);
79             header->e_phnum = le16toh(header_64->e_phnum);
80             header->e_shentsize = le16toh(header_64->e_shentsize);
81             header->e_shnum = le16toh(header_64->e_shnum);
82             header->e_shstrndx = le16toh(header_64->e_shstrndx);
83         } else {
84             return -EINVAL;
85         }
86     } else if (ELF_ENDIAN_BE(header->e_indent)) {
87         /*
88          * We use header_64 for the same reason as above.
89          */
90         header->e_type = be16toh(header_64->e_type);
91         header->e_machine = be16toh(header_64->e_machine);
92         header->e_version = be32toh(header_32->e_version);
93         if (ELF_BITS_32(header->e_indent)) {
94             header->e_entry = be32toh(header_32->e_entry);
95             header->e_phoff = be32toh(header_32->e_phoff);
96             header->e_shoff = be32toh(header_32->e_shoff);
97             header->e_flags = be32toh(header_32->e_flags);
98             header->e_ehsize = be16toh(header_32->e_ehsize);
99             header->e_phentsize = be16toh(header_32->e_phentsize);
100             header->e_phnum = be16toh(header_32->e_phnum);
101             header->e_shentsize = be16toh(header_32->e_shentsize);
102             header->e_shnum = be16toh(header_32->e_shnum);
103             header->e_shstrndx = be16toh(header_32->e_shstrndx);
104         } else if (ELF_BITS_64(header->e_indent)) {
105             header->e_entry = be64toh(header_64->e_entry);
106             header->e_phoff = be64toh(header_64->e_phoff);
107             header->e_shoff = be64toh(header_64->e_shoff);
108             header->e_flags = be32toh(header_64->e_flags);
109             header->e_ehsize = be16toh(header_64->e_ehsize);
110             header->e_phentsize = be16toh(header_64->e_phentsize);
111             header->e_phnum = be16toh(header_64->e_phnum);
112             header->e_shentsize = be16toh(header_64->e_shentsize);
113             header->e_shnum = be16toh(header_64->e_shnum);
114             header->e_shstrndx = be16toh(header_64->e_shstrndx);
115         } else {
116             return -EINVAL;
117         }
118     } else {
119         return -EINVAL;
120     }
121     return 0;
122 }
123 
124 /**
125  * Parse an ELF program header. We use the 64-bit structure
126  * `struct elf_program_header` as the output structure.
127  *
128  * On error, the negative error code is returned.
129  * On success, 0 is returned, and the header is written in the given parameter.
130  */
parse_elf_program_header(const char * code,const struct elf_header * elf,struct elf_program_header * header)131 static int parse_elf_program_header(const char *code,
132                                     const struct elf_header *elf,
133                                     struct elf_program_header *header)
134 {
135     struct elf_program_header *header_64;
136     struct elf_program_header_32 *header_32;
137 
138     if (ELF_ENDIAN_LE(elf->e_indent)) {
139         if (ELF_BITS_32(elf->e_indent)) {
140             header_32 = (struct elf_program_header_32 *)code;
141             header->p_type = le32toh(header_32->p_type);
142             header->p_flags = le32toh(header_32->p_flags);
143             header->p_offset = le32toh(header_32->p_offset);
144             header->p_vaddr = le32toh(header_32->p_vaddr);
145             header->p_paddr = le32toh(header_32->p_paddr);
146             header->p_filesz = le32toh(header_32->p_filesz);
147             header->p_memsz = le32toh(header_32->p_memsz);
148             header->p_align = le32toh(header_32->p_align);
149         } else if (ELF_BITS_64(elf->e_indent)) {
150             header_64 = (struct elf_program_header *)code;
151             header->p_type = le32toh(header_64->p_type);
152             header->p_flags = le32toh(header_64->p_flags);
153             header->p_offset = le64toh(header_64->p_offset);
154             header->p_vaddr = le64toh(header_64->p_vaddr);
155             header->p_paddr = le64toh(header_64->p_paddr);
156             header->p_filesz = le64toh(header_64->p_filesz);
157             header->p_memsz = le64toh(header_64->p_memsz);
158             header->p_align = le64toh(header_64->p_align);
159         } else {
160             return -EINVAL;
161         }
162     } else if (ELF_ENDIAN_BE(elf->e_indent)) {
163         if (ELF_BITS_32(elf->e_indent)) {
164             header_32 = (struct elf_program_header_32 *)code;
165             header->p_type = be32toh(header_32->p_type);
166             header->p_flags = be32toh(header_32->p_flags);
167             header->p_offset = be32toh(header_32->p_offset);
168             header->p_vaddr = be32toh(header_32->p_vaddr);
169             header->p_paddr = be32toh(header_32->p_paddr);
170             header->p_filesz = be32toh(header_32->p_filesz);
171             header->p_memsz = be32toh(header_32->p_memsz);
172             header->p_align = be32toh(header_32->p_align);
173         } else if (ELF_BITS_64(elf->e_indent)) {
174             header_64 = (struct elf_program_header *)code;
175             header->p_type = be32toh(header_64->p_type);
176             header->p_flags = be32toh(header_64->p_flags);
177             header->p_offset = be64toh(header_64->p_offset);
178             header->p_vaddr = be64toh(header_64->p_vaddr);
179             header->p_paddr = be64toh(header_64->p_paddr);
180             header->p_filesz = be64toh(header_64->p_filesz);
181             header->p_memsz = be64toh(header_64->p_memsz);
182             header->p_align = be64toh(header_64->p_align);
183         } else {
184             return -EINVAL;
185         }
186     } else {
187         return -EINVAL;
188     }
189     return 0;
190 }
191 
192 /**
193  * Parse an ELF section header. We use the 64-bit structure
194  * `struct elf_section_header` as the output structure.
195  *
196  * On error, the negative error code is returned.
197  * On success, 0 is returned, and the header is written in the given parameter.
198  */
parse_elf_section_header(const char * code,const struct elf_header * elf,struct elf_section_header * header)199 static int parse_elf_section_header(const char *code,
200                                     const struct elf_header *elf,
201                                     struct elf_section_header *header)
202 {
203     struct elf_section_header *header_64;
204     struct elf_section_header_32 *header_32;
205 
206     if (ELF_ENDIAN_LE(elf->e_indent)) {
207         if (ELF_BITS_32(elf->e_indent)) {
208             header_32 = (struct elf_section_header_32 *)code;
209             header->sh_name = le32toh(header_32->sh_name);
210             header->sh_type = le32toh(header_32->sh_type);
211             header->sh_flags = le32toh(header_32->sh_flags);
212             header->sh_addr = le32toh(header_32->sh_addr);
213             header->sh_offset = le32toh(header_32->sh_offset);
214             header->sh_size = le32toh(header_32->sh_size);
215             header->sh_link = le32toh(header_32->sh_link);
216             header->sh_info = le32toh(header_32->sh_info);
217             header->sh_addralign = le32toh(header_32->sh_addralign);
218             header->sh_entsize = le32toh(header_32->sh_entsize);
219         } else if (ELF_BITS_64(elf->e_indent)) {
220             header_64 = (struct elf_section_header *)code;
221             header->sh_name = le32toh(header_64->sh_name);
222             header->sh_type = le32toh(header_64->sh_type);
223             header->sh_flags = le64toh(header_64->sh_flags);
224             header->sh_addr = le64toh(header_64->sh_addr);
225             header->sh_offset = le64toh(header_64->sh_offset);
226             header->sh_size = le64toh(header_64->sh_size);
227             header->sh_link = le32toh(header_64->sh_link);
228             header->sh_info = le32toh(header_64->sh_info);
229             header->sh_addralign = le64toh(header_64->sh_addralign);
230             header->sh_entsize = le64toh(header_64->sh_entsize);
231         } else {
232             return -EINVAL;
233         }
234     } else if (ELF_ENDIAN_BE(elf->e_indent)) {
235         if (ELF_BITS_32(elf->e_indent)) {
236             header_32 = (struct elf_section_header_32 *)code;
237             header->sh_name = be32toh(header_32->sh_name);
238             header->sh_type = be32toh(header_32->sh_type);
239             header->sh_flags = be32toh(header_32->sh_flags);
240             header->sh_addr = be32toh(header_32->sh_addr);
241             header->sh_offset = be32toh(header_32->sh_offset);
242             header->sh_size = be32toh(header_32->sh_size);
243             header->sh_link = be32toh(header_32->sh_link);
244             header->sh_info = be32toh(header_32->sh_info);
245             header->sh_addralign = be32toh(header_32->sh_addralign);
246             header->sh_entsize = be32toh(header_32->sh_entsize);
247         } else if (ELF_BITS_64(elf->e_indent)) {
248             header_64 = (struct elf_section_header *)code;
249             header->sh_name = be32toh(header_64->sh_name);
250             header->sh_type = be32toh(header_64->sh_type);
251             header->sh_flags = be64toh(header_64->sh_flags);
252             header->sh_addr = be64toh(header_64->sh_addr);
253             header->sh_offset = be64toh(header_64->sh_offset);
254             header->sh_size = be64toh(header_64->sh_size);
255             header->sh_link = be32toh(header_64->sh_link);
256             header->sh_info = be32toh(header_64->sh_info);
257             header->sh_addralign = be64toh(header_64->sh_addralign);
258             header->sh_entsize = be64toh(header_64->sh_entsize);
259         } else {
260             return -EINVAL;
261         }
262     } else {
263         return -EINVAL;
264     }
265     return 0;
266 }
267 
elf_free(struct elf_file * elf)268 void elf_free(struct elf_file *elf)
269 {
270     if (elf->s_headers)
271         free(elf->s_headers);
272     if (elf->p_headers)
273         free(elf->p_headers);
274     free(elf);
275 }
276 
elf_parse_file(const char * code,struct elf_info * info)277 struct elf_file *elf_parse_file(const char *code, struct elf_info*info)
278 {
279     struct elf_file *elf;
280     int err;
281     int i;
282 
283     elf = malloc(sizeof(*elf));
284     if (!elf)
285         return NULL;
286 
287     err = parse_elf_header(code, &elf->header);
288     if (err)
289         goto out_free_elf;
290 
291     /* Allocate memory for program headers and section headers */
292     err = -ENOMEM;
293     elf->p_headers = malloc(sizeof(struct elf_program_header) * elf->header.e_phnum);
294 
295     if (!elf->p_headers)
296         goto out_free_elf;
297     elf->s_headers = malloc(sizeof(struct elf_section_header) * elf->header.e_shnum);
298     if (!elf->s_headers)
299         goto out_free_elf_p;
300 
301     /* Parse program headers and section headers */
302     for (i = 0; i < elf->header.e_phnum; ++i) {
303         err = parse_elf_program_header(code + elf->header.e_phoff
304                                            + elf->header.e_phentsize * i,
305                                        &elf->header,
306                                        &elf->p_headers[i]);
307         info->phdr[i] = elf->p_headers[i];
308         if (err)
309             goto out_free_all;
310     }
311     for (i = 0; i < elf->header.e_shnum; ++i) {
312         err = parse_elf_section_header(code + elf->header.e_shoff
313                                            + elf->header.e_shentsize * i,
314                                        &elf->header,
315                                        &elf->s_headers[i]);
316         if (err)
317             goto out_free_all;
318     }
319     return elf;
320 
321 out_free_all:
322     free(elf->s_headers);
323 out_free_elf_p:
324     free(elf->p_headers);
325 out_free_elf:
326     free(elf);
327     return NULL;
328 }
329