bfelf_loader.h
Go to the documentation of this file.
1 /*
2  * Bareflank Hypervisor
3  *
4  * Copyright (C) 2015 Assured Information Security, Inc.
5  * Author: Rian Quinn <quinnr@ainfosec.com>
6  * Author: Brendan Kerrigan <kerriganb@ainfosec.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
27 #ifndef BFELF_LOADER_H
28 #define BFELF_LOADER_H
29 
30 #include <debug.h>
31 #include <constants.h>
32 #include <crt.h>
33 #include <error_codes.h>
34 #include <types.h>
35 
36 #pragma GCC system_header
37 
38 #pragma pack(push, 1)
39 
40 /* @cond */
41 
42 #ifdef __cplusplus
43 #define scast(a, b) (static_cast<a>(b))
44 #else
45 #define scast(a, b) ((a)(b))
46 #endif
47 
48 #ifdef __cplusplus
49 #define rcast(a, b) (reinterpret_cast<a>(b))
50 #else
51 #define rcast(a, b) ((a)(b))
52 #endif
53 
54 #ifdef __cplusplus
55 #define add(a, b, c) (reinterpret_cast<a>(reinterpret_cast<const char *>(b) + (c)))
56 #else
57 #define add(a, b, c) ((a)((const char *)(b) + (c)))
58 #endif
59 
60 /* @endcond */
61 
62 #ifdef __cplusplus
63 extern "C" {
64 #endif
65 
66 /* ---------------------------------------------------------------------------------------------- */
67 /* ELF Defines */
68 /* ---------------------------------------------------------------------------------------------- */
69 
70 /* @cond */
71 
72 #ifndef BFELF_MAX_NEEDED
73 #define BFELF_MAX_NEEDED (25)
74 #endif
75 
76 #ifndef BFELF_MAX_SEGMENTS
77 #define BFELF_MAX_SEGMENTS (4)
78 #endif
79 
80 /* @endcond */
81 
82 /* ---------------------------------------------------------------------------------------------- */
83 /* ELF Data Types */
84 /* ---------------------------------------------------------------------------------------------- */
85 
86 /*
87  * Data Representation
88  *
89  * The following is defined in the ELF 64bit file format specification:
90  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 2
91  */
92 
93 /* @cond */
94 
95 typedef uint64_t bfelf64_addr;
96 typedef uint64_t bfelf64_off;
97 typedef uint16_t bfelf64_half;
98 typedef uint32_t bfelf64_word;
99 typedef int32_t bfelf64_sword;
100 typedef uint64_t bfelf64_xword;
101 typedef int64_t bfelf64_sxword;
102 
103 /* @endcond */
104 
105 /* ---------------------------------------------------------------------------------------------- */
106 /* ELF Error Codes */
107 /* ---------------------------------------------------------------------------------------------- */
108 
109 /* @cond */
110 
111 static inline int64_t
112 private_error(const char *header, const char *msg, const char *func, int line, int64_t code)
113 {
114  ALERT("%s [%d] %s: %s\n", func, line, header, msg);
115  return code;
116 }
117 
118 #define bfinvalid_argument(a) \
119  private_error("invalid argument", a, __func__, __LINE__, BFELF_ERROR_INVALID_ARG);
120 
121 #define bfinvalid_file(a) \
122  private_error("invalid file", a, __func__, __LINE__, BFELF_ERROR_INVALID_FILE);
123 
124 #define bfinvalid_index(a) \
125  private_error("invalid index", a, __func__, __LINE__, BFELF_ERROR_INVALID_INDEX);
126 
127 #define bfinvalid_signature(a) \
128  private_error("invalid signature", a, __func__, __LINE__, BFELF_ERROR_INVALID_SIGNATURE);
129 
130 #define bfunsupported_file(a) \
131  private_error("unsupported elf file", a, __func__, __LINE__, BFELF_ERROR_UNSUPPORTED_FILE);
132 
133 #define bfloader_full(a) \
134  private_error("loader full", a, __func__, __LINE__, BFELF_ERROR_LOADER_FULL);
135 
136 #define bfno_such_symbol(a) \
137  private_error("no such symbol", a, __func__, __LINE__, BFELF_ERROR_NO_SUCH_SYMBOL);
138 
139 #define bfunsupported_rel(a) \
140  private_error("unsupported relocation", a, __func__, __LINE__, BFELF_ERROR_UNSUPPORTED_RELA);
141 
142 /* @endcond */
143 
144 /* ---------------------------------------------------------------------------------------------- */
145 /* ELF Helpers */
146 /* ---------------------------------------------------------------------------------------------- */
147 
148 /* @cond */
149 
150 static inline int64_t
151 private_strcmp(const char *s1, const char *s2)
152 {
153  while (*s1 && (*s1 == *s2))
154  s1++, s2++;
155 
156  return *s1 == *s2 ? BFELF_SUCCESS : BFELF_ERROR_MISMATCH;
157 }
158 
159 /* @endcond */
160 
161 /* ---------------------------------------------------------------------------------------------- */
162 /* ELF File Definition */
163 /* ---------------------------------------------------------------------------------------------- */
164 
165 struct bfelf_dyn;
166 struct bfelf_sym;
167 struct bfelf_rela;
168 struct bfelf_shdr;
169 struct bfelf_phdr;
170 struct bfelf_ehdr;
171 
208 {
209  bfelf64_word perm;
210  bfelf64_off mem_offset;
211  bfelf64_off file_offset;
212  bfelf64_xword memsz;
213  bfelf64_xword filesz;
214  bfelf64_addr virt_addr;
215 };
216 
217 /*
218  * ELF File
219  *
220  * The following is used by this API to store information about the ELF file
221  * being used.
222  *
223  * @cond
224  */
225 struct bfelf_file_t
226 {
227  uint64_t filesz;
228  const char *file;
229 
230  char *exec_addr;
231  char *exec_virt;
232 
233  bfelf64_off entry;
234 
235  bfelf64_xword num_load_instr;
236  struct bfelf_load_instr load_instr[BFELF_MAX_SEGMENTS];
237 
238  bfelf64_xword num_loadable_segments;
239  const struct bfelf_phdr *loadable_segments[BFELF_MAX_SEGMENTS];
240 
241  bfelf64_addr start_addr;
242  bfelf64_xword total_memsz;
243 
244  bfelf64_xword num_needed;
245  bfelf64_xword needed[BFELF_MAX_NEEDED];
246 
247  const struct bfelf_ehdr *ehdr;
248  const struct bfelf_phdr *phdrtab;
249  const struct bfelf_shdr *shdrtab;
250 
251  bfelf64_addr dynoff;
252 
253  const char *strtab;
254  const char *shstrtab;
255 
256  bfelf64_word nbucket;
257  bfelf64_word nchain;
258  const bfelf64_word *bucket;
259  const bfelf64_word *chain;
260  const bfelf64_word *hash;
261 
262  bfelf64_xword dynnum;
263  const struct bfelf_dyn *dyntab;
264 
265  bfelf64_xword symnum;
266  const struct bfelf_sym *symtab;
267 
268  bfelf64_xword relanum_dyn;
269  const struct bfelf_rela *relatab_dyn;
270 
271  bfelf64_xword relanum_plt;
272  const struct bfelf_rela *relatab_plt;
273 
274  bfelf64_addr init;
275  bfelf64_addr fini;
276 
277  bfelf64_addr init_array;
278  bfelf64_xword init_arraysz;
279 
280  bfelf64_addr fini_array;
281  bfelf64_xword fini_arraysz;
282 
283  bfelf64_addr eh_frame;
284  bfelf64_xword eh_framesz;
285 
286  bfelf64_xword flags_1;
287  bfelf64_xword stack_flags;
288 
289  bfelf64_addr relaro_vaddr;
290  bfelf64_xword relaro_memsz;
291 
292  bfelf64_word added;
293 };
294 
295 /* @endcond */
296 
297 /* ---------------------------------------------------------------------------------------------- */
298 /* ELF File Header */
299 /* ---------------------------------------------------------------------------------------------- */
300 
301 /*
302  * e_ident indexes
303  *
304  * The following is defined in the ELF 64bit file format specification:
305  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 3
306  *
307  * @cond
308  */
309 #define bfei_mag0 scast(bfelf64_sword, 0)
310 #define bfei_mag1 scast(bfelf64_sword, 1)
311 #define bfei_mag2 scast(bfelf64_sword, 2)
312 #define bfei_mag3 scast(bfelf64_sword, 3)
313 #define bfei_class scast(bfelf64_sword, 4)
314 #define bfei_data scast(bfelf64_sword, 5)
315 #define bfei_version scast(bfelf64_sword, 6)
316 #define bfei_osabi scast(bfelf64_sword, 7)
317 #define bfei_abiversion scast(bfelf64_sword, 8)
318 #define bfei_pad scast(bfelf64_sword, 9)
319 #define bfei_nident scast(bfelf64_sword, 16)
320 
321 /* @endcond */
322 
323 /*
324  * ELF Class Types
325  *
326  * The following is defined in the ELF 64bit file format specification:
327  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 5
328  *
329  * @cond
330  */
331 #define bfelfclass32 scast(unsigned char, 1)
332 #define bfelfclass64 scast(unsigned char, 2)
333 
334 /* @endcond */
335 
336 /*
337  * ELF Data Types
338  *
339  * The following is defined in the ELF 64bit file format specification:
340  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 5
341  *
342  * @cond
343  */
344 #define bfelfdata2lsb scast(unsigned char, 1)
345 #define bfelfdata2msb scast(unsigned char, 2)
346 
347 /* @endcond */
348 
349 /*
350  * ELF Version
351  *
352  * The following is defined in the ELF 64bit file format specification:
353  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 4
354  *
355  * @cond
356  */
357 #define bfev_current scast(unsigned char, 1)
358 
359 /* @endcond */
360 
361 /*
362  * ELF OS / ABI Types
363  *
364  * The following is defined in the ELF 64bit file format specification:
365  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 5
366  *
367  * @cond
368  */
369 #define bfelfosabi_sysv scast(unsigned char, 0)
370 #define bfelfosabi_hpux scast(unsigned char, 1)
371 #define bfelfosabi_standalone scast(unsigned char, 255)
372 
373 /* @endcond */
374 
375 /*
376  * ELF Types
377  *
378  * The following is defined in the ELF 64bit file format specification:
379  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 5
380  *
381  * @cond
382  */
383 #define bfet_none scast(bfelf64_half, 0)
384 #define bfet_rel scast(bfelf64_half, 1)
385 #define bfet_exec scast(bfelf64_half, 2)
386 #define bfet_dyn scast(bfelf64_half, 3)
387 #define bfet_core scast(bfelf64_half, 4)
388 #define bfet_loos scast(bfelf64_half, 0xFE00)
389 #define bfet_hios scast(bfelf64_half, 0xFEFF)
390 #define bfet_loproc scast(bfelf64_half, 0xFF00)
391 #define bfet_hiproc scast(bfelf64_half, 0xFFFF)
392 
393 /* @endcond */
394 
395 /*
396  * ELF Machine Codes
397  *
398  * The following is defined in the Linux kernel sources:
399  * linux/include/uapi/linux/elf-em.h
400  *
401  * @cond
402  */
403 #define bfem_none scast(bfelf64_half, 0)
404 #define bfem_m32 scast(bfelf64_half, 1)
405 #define bfem_sparc scast(bfelf64_half, 2)
406 #define bfem_386 scast(bfelf64_half, 3)
407 #define bfem_68k scast(bfelf64_half, 4)
408 #define bfem_88k scast(bfelf64_half, 5)
409 #define bfem_486 scast(bfelf64_half, 6)
410 #define bfem_860 scast(bfelf64_half, 7)
411 #define bfem_mips scast(bfelf64_half, 8)
412 #define bfem_mips_rs3_le scast(bfelf64_half, 10)
413 #define bfem_mips_rs4_be scast(bfelf64_half, 11)
414 #define bfem_parisc scast(bfelf64_half, 15)
415 #define bfem_sparc32plus scast(bfelf64_half, 18)
416 #define bfem_ppc scast(bfelf64_half, 20)
417 #define bfem_ppc64 scast(bfelf64_half, 21)
418 #define bfem_spu scast(bfelf64_half, 23)
419 #define bfem_arm scast(bfelf64_half, 40)
420 #define bfem_sh scast(bfelf64_half, 42)
421 #define bfem_sparcv9 scast(bfelf64_half, 43)
422 #define bfem_h8_300 scast(bfelf64_half, 46)
423 #define bfem_ia_64 scast(bfelf64_half, 50)
424 #define bfem_x86_64 scast(bfelf64_half, 62)
425 #define bfem_s390 scast(bfelf64_half, 22)
426 #define bfem_cris scast(bfelf64_half, 76)
427 #define bfem_v850 scast(bfelf64_half, 87)
428 #define bfem_m32r scast(bfelf64_half, 88)
429 #define bfem_mn10300 scast(bfelf64_half, 89)
430 #define bfem_openrisc scast(bfelf64_half, 92)
431 #define bfem_blackfin scast(bfelf64_half, 106)
432 #define bfem_altera_nios2 scast(bfelf64_half, 113)
433 #define bfem_ti_c6000 scast(bfelf64_half, 140)
434 #define bfem_aarch64 scast(bfelf64_half, 183)
435 #define bfem_frv scast(bfelf64_half, 0x5441)
436 #define bfem_avr32 scast(bfelf64_half, 0x18AD)
437 #define bfem_alpha scast(bfelf64_half, 0x9026)
438 #define bfem_cygnus_v850 scast(bfelf64_half, 0x9080)
439 #define bfem_cygnus_m32r scast(bfelf64_half, 0x9041)
440 #define bfem_s390_old scast(bfelf64_half, 0xA390)
441 #define bfem_cygnus_mn10300 scast(bfelf64_half, 0xBEEF)
442 
443 /* @endcond */
444 
445 /*
446  * ELF File Header
447  *
448  * The following is defined in the ELF 64bit file format specification:
449  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 3
450  *
451  * The file header is located at the beginning of the file, and is used to
452  * locate the other parts of the file.
453  *
454  * @cond
455  */
456 struct bfelf_ehdr
457 {
458  unsigned char e_ident[bfei_nident];
459  bfelf64_half e_type;
460  bfelf64_half e_machine;
461  bfelf64_word e_version;
462  bfelf64_addr e_entry;
463  bfelf64_off e_phoff;
464  bfelf64_off e_shoff;
465  bfelf64_word e_flags;
466  bfelf64_half e_ehsize;
467  bfelf64_half e_phentsize;
468  bfelf64_half e_phnum;
469  bfelf64_half e_shentsize;
470  bfelf64_half e_shnum;
471  bfelf64_half e_shstrndx;
472 };
473 
474 /* @endcond */
475 
476 /* ---------------------------------------------------------------------------------------------- */
477 /* ELF Section Header Table */
478 /* ---------------------------------------------------------------------------------------------- */
479 
480 /*
481  * ELF Section Type
482  *
483  * The following is defined in the ELF 64bit file format specification:
484  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 7
485  *
486  * @cond
487  */
488 #define bfsht_null scast(bfelf64_word, 0)
489 #define bfsht_progbits scast(bfelf64_word, 1)
490 #define bfsht_symtab scast(bfelf64_word, 2)
491 #define bfsht_strtab scast(bfelf64_word, 3)
492 #define bfsht_rela scast(bfelf64_word, 4)
493 #define bfsht_hash scast(bfelf64_word, 5)
494 #define bfsht_dynamic scast(bfelf64_word, 6)
495 #define bfsht_note scast(bfelf64_word, 7)
496 #define bfsht_nobits scast(bfelf64_word, 8)
497 #define bfsht_rel scast(bfelf64_word, 9)
498 #define bfsht_shlib scast(bfelf64_word, 10)
499 #define bfsht_dynsym scast(bfelf64_word, 11)
500 #define bfsht_init_array scast(bfelf64_word, 14)
501 #define bfsht_fini_array scast(bfelf64_word, 15)
502 #define bfsht_loos scast(bfelf64_word, 0x60000000)
503 #define bfsht_hios scast(bfelf64_word, 0x6FFFFFFF)
504 #define bfsht_loproc scast(bfelf64_word, 0x70000000)
505 #define bfsht_x86_64_unwind scast(bfelf64_word, 0x70000001)
506 #define bfsht_hiproc scast(bfelf64_word, 0x7FFFFFFF)
507 
508 /* @endcond */
509 
510 /*
511  * ELF Section Attributes
512  *
513  * The following is defined in the ELF 64bit file format specification:
514  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 8
515  *
516  * @cond
517  */
518 #define bfshf_write scast(bfelf64_xword, 0x1)
519 #define bfshf_alloc scast(bfelf64_xword, 0x2)
520 #define bfshf_execinstr scast(bfelf64_xword, 0x4)
521 #define bfshf_maskos scast(bfelf64_xword, 0x0F000000)
522 #define bfshf_maskproc scast(bfelf64_xword, 0xF0000000)
523 #define bfshf_undocumneted scast(bfelf64_xword, 0x00000060)
524 
525 #define bfshf_a (bfshf_alloc)
526 #define bfshf_wa (bfshf_write | bfshf_alloc)
527 #define bfshf_ai (bfshf_alloc | bfshf_write | bfshf_undocumneted)
528 
529 /* @endcond */
530 
531 /*
532  * ELF Section Header Entry
533  *
534  * The following is defined in the ELF 64bit file format specification:
535  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 6
536  *
537  * Sections contain all the information in an ELF file, except for the ELF
538  * header, program header table, and section header table. Sections are
539  * identified by an index into the section header table.
540  *
541  * @cond
542  */
543 struct bfelf_shdr
544 {
545  bfelf64_word sh_name;
546  bfelf64_word sh_type;
547  bfelf64_xword sh_flags;
548  bfelf64_addr sh_addr;
549  bfelf64_off sh_offset;
550  bfelf64_xword sh_size;
551  bfelf64_word sh_link;
552  bfelf64_word sh_info;
553  bfelf64_xword sh_addralign;
554  bfelf64_xword sh_entsize;
555 };
556 
557 /* @endcond */
558 
559 /* ---------------------------------------------------------------------------------------------- */
560 /* ELF Dynamic Section */
561 /* ---------------------------------------------------------------------------------------------- */
562 
563 /*
564  * ELF Dynamic Table Entry Tags
565  *
566  * The following is defined in the ELF 64bit file format specification:
567  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 14
568  *
569  * @cond
570  */
571 #define bfdt_null scast(bfelf64_xword, 0)
572 #define bfdt_needed scast(bfelf64_xword, 1)
573 #define bfdt_pltrelsz scast(bfelf64_xword, 2)
574 #define bfdt_pltgot scast(bfelf64_xword, 3)
575 #define bfdt_hash scast(bfelf64_xword, 4)
576 #define bfdt_strtab scast(bfelf64_xword, 5)
577 #define bfdt_symtab scast(bfelf64_xword, 6)
578 #define bfdt_rela scast(bfelf64_xword, 7)
579 #define bfdt_relasz scast(bfelf64_xword, 8)
580 #define bfdt_relaent scast(bfelf64_xword, 9)
581 #define bfdt_strsz scast(bfelf64_xword, 10)
582 #define bfdt_syment scast(bfelf64_xword, 11)
583 #define bfdt_init scast(bfelf64_xword, 12)
584 #define bfdt_fini scast(bfelf64_xword, 13)
585 #define bfdt_soname scast(bfelf64_xword, 14)
586 #define bfdt_rpath scast(bfelf64_xword, 15)
587 #define bfdt_symbolic scast(bfelf64_xword, 16)
588 #define bfdt_rel scast(bfelf64_xword, 17)
589 #define bfdt_relsz scast(bfelf64_xword, 18)
590 #define bfdt_relent scast(bfelf64_xword, 19)
591 #define bfdt_pltrel scast(bfelf64_xword, 20)
592 #define bfdt_debug scast(bfelf64_xword, 21)
593 #define bfdt_textrel scast(bfelf64_xword, 22)
594 #define bfdt_jmprel scast(bfelf64_xword, 23)
595 #define bfdt_bind_now scast(bfelf64_xword, 24)
596 #define bfdt_init_array scast(bfelf64_xword, 25)
597 #define bfdt_fini_array scast(bfelf64_xword, 26)
598 #define bfdt_init_arraysz scast(bfelf64_xword, 27)
599 #define bfdt_fini_arraysz scast(bfelf64_xword, 28)
600 #define bfdt_loos scast(bfelf64_xword, 0x60000000)
601 #define bfdt_relacount scast(bfelf64_xword, 0x6ffffff9)
602 #define bfdt_relcount scast(bfelf64_xword, 0x6ffffffa)
603 #define bfdt_flags_1 scast(bfelf64_xword, 0x6ffffffb)
604 #define bfdt_hios scast(bfelf64_xword, 0x6FFFFFFF)
605 #define bfdt_loproc scast(bfelf64_xword, 0x70000000)
606 #define bfdt_hiproc scast(bfelf64_xword, 0x7FFFFFFF)
607 
608 #define bfdf_1_now scast(bfelf64_xword, 0x00000001)
609 #define bfdf_1_global scast(bfelf64_xword, 0x00000002)
610 #define bfdf_1_group scast(bfelf64_xword, 0x00000004)
611 #define bfdf_1_nodelete scast(bfelf64_xword, 0x00000008)
612 #define bfdf_1_loadfltr scast(bfelf64_xword, 0x00000010)
613 #define bfdf_1_initfirst scast(bfelf64_xword, 0x00000020)
614 #define bfdf_1_noopen scast(bfelf64_xword, 0x00000040)
615 #define bfdf_1_origin scast(bfelf64_xword, 0x00000080)
616 #define bfdf_1_direct scast(bfelf64_xword, 0x00000100)
617 #define bfdf_1_trans scast(bfelf64_xword, 0x00000200)
618 #define bfdf_1_interpose scast(bfelf64_xword, 0x00000400)
619 #define bfdf_1_nodeflib scast(bfelf64_xword, 0x00000800)
620 #define bfdf_1_nodump scast(bfelf64_xword, 0x00001000)
621 #define bfdf_1_confalt scast(bfelf64_xword, 0x00002000)
622 #define bfdf_1_endfiltee scast(bfelf64_xword, 0x00004000)
623 #define bfdf_1_dispreldne scast(bfelf64_xword, 0x00008000)
624 #define bfdf_1_disprelpnd scast(bfelf64_xword, 0x00010000)
625 #define bfdf_1_nodirect scast(bfelf64_xword, 0x00020000)
626 #define bfdf_1_ignmuldef scast(bfelf64_xword, 0x00040000)
627 #define bfdf_1_noksyms scast(bfelf64_xword, 0x00080000)
628 #define bfdf_1_nohdr scast(bfelf64_xword, 0x00100000)
629 #define bfdf_1_edited scast(bfelf64_xword, 0x00200000)
630 #define bfdf_1_noreloc scast(bfelf64_xword, 0x00400000)
631 #define bfdf_1_symintpose scast(bfelf64_xword, 0x00800000)
632 #define bfdf_1_globaudit scast(bfelf64_xword, 0x01000000)
633 #define bfdf_1_singleton scast(bfelf64_xword, 0x02000000)
634 #define bfdf_1_pie scast(bfelf64_xword, 0x08000000)
635 
636 /* @endcond */
637 
638 /*
639  * ELF Dynamic Table
640  *
641  * The following is defined in the ELF 64bit file format specification:
642  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 14
643  *
644  * NOTE: The spec actually uses a union, but the use of a union goes against
645  * the C++ Core Guidelines, and Windows seems to get really mad. There really
646  * is not need for a union since the type size if the same. For this reason,
647  * we simply use d_val and cast when needed.
648  *
649  * @cond
650  */
651 struct bfelf_dyn
652 {
653  bfelf64_sxword d_tag;
654  bfelf64_xword d_val;
655 };
656 
657 /* @endcond */
658 
659 /* ---------------------------------------------------------------------------------------------- */
660 /* ELF Symbol Table */
661 /* ---------------------------------------------------------------------------------------------- */
662 
663 /*
664  * ELF Symbol Bindings
665  *
666  * The following is defined in the ELF 64bit file format specification:
667  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 10
668  *
669  * @cond
670  */
671 #define bfstb_local scast(unsigned char, 0)
672 #define bfstb_global scast(unsigned char, 1)
673 #define bfstb_weak scast(unsigned char, 2)
674 #define bfstb_loos scast(unsigned char, 10)
675 #define bfstb_hios scast(unsigned char, 12)
676 #define bfstb_loproc scast(unsigned char, 13)
677 #define bfstb_hiproc scast(unsigned char, 15)
678 
679 /* @endcond */
680 
681 /*
682  * ELF Symbol Types
683  *
684  * The following is defined in the ELF 64bit file format specification:
685  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 10
686  *
687  * @cond
688  */
689 #define bfstt_notype scast(unsigned char, 0)
690 #define bfstt_object scast(unsigned char, 1)
691 #define bfstt_func scast(unsigned char, 2)
692 #define bfstt_section scast(unsigned char, 3)
693 #define bfstt_file scast(unsigned char, 4)
694 #define bfstt_loos scast(unsigned char, 10)
695 #define bfstt_hios scast(unsigned char, 12)
696 #define bfstt_loproc scast(unsigned char, 13)
697 #define bfstt_hiproc scast(unsigned char, 15)
698 
699 /* @endcond */
700 
701 /*
702  * ELF Symbol Info Algorithms
703  *
704  * The following is defined in the ELF 64bit file format specification:
705  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 11
706  *
707  * @cond
708  */
709 #define BFELF_SYM_BIND(x) ((x) >> 4)
710 #define BFELF_SYM_TYPE(x) ((x)&0xF)
711 
712 /* @endcond */
713 
714 /*
715  * ELF Undefined Symbol Index
716  *
717  * The following is defined in the ELF 64bit file format specification:
718  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 9
719  *
720  * @cond
721  */
722 #define STN_UNDEF 0
723 
724 /* @endcond */
725 
726 /*
727  * ELF Symbol
728  *
729  * The following is defined in the ELF 64bit file format specification:
730  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 9
731  *
732  * @cond
733  */
734 struct bfelf_sym
735 {
736  bfelf64_word st_name;
737  unsigned char st_info;
738  unsigned char st_other;
739  bfelf64_half st_shndx;
740  bfelf64_addr st_value;
741  bfelf64_xword st_size;
742 };
743 
744 /* @endcond */
745 
746 /* ---------------------------------------------------------------------------------------------- */
747 /* ELF Relocations */
748 /* ---------------------------------------------------------------------------------------------- */
749 
750 /*
751  * System V ABI 64bit Relocations
752  *
753  * The following is defined in the ELF 64bit file format specification:
754  * http://www.x86-64.org/documentation/abi.pdf, page 71
755  *
756  * @cond
757  */
758 #define BFR_X86_64_64 scast(bfelf64_xword, 1)
759 #define BFR_X86_64_GLOB_DAT scast(bfelf64_xword, 6)
760 #define BFR_X86_64_JUMP_SLOT scast(bfelf64_xword, 7)
761 #define BFR_X86_64_RELATIVE scast(bfelf64_xword, 8)
762 
763 /* @endcond */
764 
765 /*
766  * ELF Relocation
767  *
768  * The following is defined in the ELF 64bit file format specification:
769  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 11
770  *
771  * @cond
772  */
773 struct bfelf_rel
774 {
775  bfelf64_addr r_offset;
776  bfelf64_xword r_info;
777 };
778 
779 /* @endcond */
780 
781 /*
782  * ELF Relocation Addend
783  *
784  * The following is defined in the ELF 64bit file format specification:
785  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 11
786  *
787  * @cond
788  */
789 struct bfelf_rela
790 {
791  bfelf64_addr r_offset;
792  bfelf64_xword r_info;
793  bfelf64_sxword r_addend;
794 };
795 
796 /* @endcond */
797 
798 /*
799  * ELF Relocation Info Algorithms
800  *
801  * The following is defined in the ELF 64bit file format specification:
802  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 11
803  *
804  * @cond
805  */
806 #define BFELF_REL_SYM(i) ((i) >> 32)
807 #define BFELF_REL_TYPE(i) ((i)&0xFFFFFFFFL)
808 
809 /* @endcond */
810 
811 /* ---------------------------------------------------------------------------------------------- */
812 /* ELF Program Header */
813 /* ---------------------------------------------------------------------------------------------- */
814 
815 /*
816  * ELF Section Attributes
817  *
818  * The following is defined in the ELF 64bit file format specification:
819  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 12
820  *
821  * @cond
822  */
823 #define bfpt_null scast(bfelf64_word, 0)
824 #define bfpt_load scast(bfelf64_word, 1)
825 #define bfpt_dynamic scast(bfelf64_word, 2)
826 #define bfpt_interp scast(bfelf64_word, 3)
827 #define bfpt_note scast(bfelf64_word, 4)
828 #define bfpt_shlib scast(bfelf64_word, 5)
829 #define bfpt_phdr scast(bfelf64_word, 6)
830 #define bfpt_loos scast(bfelf64_word, 0x60000000)
831 #define bfpt_gnu_eh_frame scast(bfelf64_word, 0x6474e550)
832 #define bfpt_gnu_stack scast(bfelf64_word, 0x6474e551)
833 #define bfpt_gnu_relro scast(bfelf64_word, 0x6474e552)
834 #define bfpt_hios scast(bfelf64_word, 0x6FFFFFFF)
835 #define bfpt_loproc scast(bfelf64_word, 0x70000000)
836 #define bfpt_hiproc scast(bfelf64_word, 0x7FFFFFFF)
837 
838 /* @endcond */
839 
840 /*
841  * ELF Section Attributes
842  *
843  * The following is defined in the ELF 64bit file format specification:
844  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 13
845  *
846  * @cond
847  */
848 #define bfpf_x scast(bfelf64_xword, 0x1)
849 #define bfpf_w scast(bfelf64_xword, 0x2)
850 #define bfpf_r scast(bfelf64_xword, 0x4)
851 #define bfpf_maskos scast(bfelf64_xword, 0x00FF0000)
852 #define bfpf_maskproc scast(bfelf64_xword, 0xFF000000)
853 
854 /* @endcond */
855 
856 /*
857  * ELF Program Header Entry
858  *
859  * The following is defined in the ELF 64bit file format specification:
860  * http://www.uclibc.org/docs/elf-64-gen.pdf, page 12
861  *
862  * In executable and shared object files, sections are grouped into segments for
863  * loading. The program header table contains a list of entries describing
864  * each segment. This information is needed when using the ELF loader to
865  * load each segment into memory allocated by the user. For more information
866  * on how to do this, please see the unit tests.
867  *
868  * @cond
869  */
870 struct bfelf_phdr
871 {
872  bfelf64_word p_type;
873  bfelf64_word p_flags;
874  bfelf64_off p_offset;
875  bfelf64_addr p_vaddr;
876  bfelf64_addr p_paddr;
877  bfelf64_xword p_filesz;
878  bfelf64_xword p_memsz;
879  bfelf64_xword p_align;
880 };
881 
882 /* @endcond */
883 
884 /* ---------------------------------------------------------------------------------------------- */
885 /* ELF Loader Definition */
886 /* ---------------------------------------------------------------------------------------------- */
887 
888 /*
889  * ELF Loader
890  *
891  * The following structure is used to create an ELF loader, which groups up
892  * all of the ELF files used by a single program, mainly needed for global
893  * symbol searching.
894  *
895  * @cond
896  */
897 struct bfelf_loader_t
898 {
899  bfelf64_word num;
900  bfelf64_word relocated;
901  struct bfelf_file_t *efs[MAX_NUM_MODULES];
902 };
903 
904 /* @endcond */
905 
906 /* ---------------------------------------------------------------------------------------------- */
907 /* ELF Symbol Table Implementation */
908 /* ---------------------------------------------------------------------------------------------- */
909 
910 /* @cond */
911 
912 static inline unsigned long
913 private_hash(const char *name)
914 {
915  unsigned long h = 0, g;
916 
917  while (*name)
918  {
919  char c = *name++;
920  unsigned char uc = scast(unsigned char, c);
921 
922  if (c >= 0)
923  {
924  h = (h << 4) + uc;
925  }
926  else
927  {
928  h = (h << 4) - uc;
929  }
930 
931  if ((g = (h & 0xf0000000)))
932  {
933  h ^= g >> 24;
934  }
935 
936  h &= 0x0fffffff;
937  }
938 
939  return h;
940 }
941 
942 static inline int64_t
943 private_get_sym_by_hash(struct bfelf_file_t *ef, const char *name, const struct bfelf_sym **sym)
944 {
945  int64_t ret = 0;
946  bfelf64_word i = 0;
947  unsigned long x = private_hash(name);
948 
949  i = ef->bucket[x % ef->nbucket];
950  while (i > STN_UNDEF && i < ef->nchain)
951  {
952  const char *str = 0;
953 
954  *sym = &(ef->symtab[i]);
955  str = &(ef->strtab[(*sym)->st_name]);
956 
957  ret = private_strcmp(name, str);
958  if (ret == BFELF_ERROR_MISMATCH)
959  {
960  i = ef->chain[i];
961  continue;
962  }
963 
964  return BFELF_SUCCESS;
965  }
966 
968 }
969 
970 static inline int64_t
971 private_get_sym_by_name(struct bfelf_file_t *ef, const char *name, const struct bfelf_sym **sym)
972 {
973  int64_t ret = 0;
974  bfelf64_word i = 0;
975 
976  if (ef->hash != 0)
977  {
978  return private_get_sym_by_hash(ef, name, sym);
979  }
980 
981  for (i = 0; i < ef->symnum; i++)
982  {
983  const char *str = 0;
984 
985  *sym = &(ef->symtab[i]);
986  str = &(ef->strtab[(*sym)->st_name]);
987 
988  ret = private_strcmp(name, str);
989  if (ret == BFELF_ERROR_MISMATCH)
990  {
991  continue;
992  }
993 
994  return BFELF_SUCCESS;
995  }
996 
998 }
999 
1000 static inline int64_t
1001 private_get_sym_global(
1002  struct bfelf_loader_t *loader,
1003  const char *name,
1004  struct bfelf_file_t **ef_found,
1005  const struct bfelf_sym **sym)
1006 {
1007  int64_t ret = 0;
1008  bfelf64_word i = 0;
1009  const struct bfelf_sym *found_sym = 0;
1010  struct bfelf_file_t *ef_ignore = *ef_found;
1011 
1012  *sym = 0;
1013  *ef_found = 0;
1014 
1015  for (i = 0; i < loader->num; i++)
1016  {
1017  if (loader->efs[i] == ef_ignore)
1018  {
1019  continue;
1020  }
1021 
1022  ret = private_get_sym_by_name(loader->efs[i], name, &found_sym);
1023  if (ret == BFELF_ERROR_NO_SUCH_SYMBOL)
1024  {
1025  continue;
1026  }
1027 
1028  if (found_sym->st_value == 0)
1029  continue;
1030 
1031  *sym = found_sym;
1032  *ef_found = loader->efs[i];
1033 
1034  if (BFELF_SYM_BIND(found_sym->st_info) == bfstb_weak)
1035  {
1036  continue;
1037  }
1038 
1039  return BFELF_SUCCESS;
1040  }
1041 
1042  if (*sym != 0)
1043  {
1044  return BFELF_SUCCESS;
1045  }
1046 
1047  return bfno_such_symbol(name);
1048 }
1049 
1050 /* @endcond */
1051 
1052 /* ---------------------------------------------------------------------------------------------- */
1053 /* ELF Relocations Implementation */
1054 /* ---------------------------------------------------------------------------------------------- */
1055 
1056 /* @cond */
1057 
1058 static inline int64_t
1059 private_relocate_symbol(
1060  struct bfelf_loader_t *loader, struct bfelf_file_t *ef, const struct bfelf_rela *rela)
1061 {
1062  int64_t ret = 0;
1063  const char *str = 0;
1064  const struct bfelf_sym *found_sym = 0;
1065  struct bfelf_file_t *found_ef = ef;
1066  bfelf64_addr *ptr = rcast(bfelf64_addr *, ef->exec_addr + rela->r_offset - ef->start_addr);
1067 
1068  if (BFELF_REL_TYPE(rela->r_info) == BFR_X86_64_RELATIVE)
1069  {
1070  *ptr = rcast(bfelf64_addr, ef->exec_virt + rela->r_addend);
1071  return BFELF_SUCCESS;
1072  }
1073 
1074  found_sym = &(ef->symtab[BFELF_REL_SYM(rela->r_info)]);
1075 
1076  if (BFELF_SYM_BIND(found_sym->st_info) == bfstb_weak)
1077  {
1078  found_ef = 0;
1079  }
1080 
1081  if (found_sym->st_value == 0 || found_ef == 0)
1082  {
1083  str = &(ef->strtab[found_sym->st_name]);
1084 
1085  ret = private_get_sym_global(loader, str, &found_ef, &found_sym);
1086  if (ret != BFELF_SUCCESS)
1087  {
1088  return ret;
1089  }
1090  }
1091 
1092  *ptr = rcast(bfelf64_addr, found_ef->exec_virt + found_sym->st_value);
1093 
1094  switch (BFELF_REL_TYPE(rela->r_info))
1095  {
1096  case BFR_X86_64_64:
1097  *ptr += scast(bfelf64_addr, rela->r_addend);
1098  break;
1099 
1100  case BFR_X86_64_GLOB_DAT:
1101  case BFR_X86_64_JUMP_SLOT:
1102  break;
1103 
1104  default:
1105  return bfunsupported_rel(str);
1106  }
1107 
1108  return BFELF_SUCCESS;
1109 }
1110 
1111 static inline int64_t
1112 private_relocate_symbols(struct bfelf_loader_t *loader, struct bfelf_file_t *ef)
1113 {
1114  int64_t ret = 0;
1115  bfelf64_word i = 0;
1116 
1117  for (i = 0; i < ef->relanum_dyn; i++)
1118  {
1119  const struct bfelf_rela *rela = &(ef->relatab_dyn[i]);
1120 
1121  ret = private_relocate_symbol(loader, ef, rela);
1122  if (ret != BFELF_SUCCESS)
1123  {
1124  return ret;
1125  }
1126  }
1127 
1128  for (i = 0; i < ef->relanum_plt; i++)
1129  {
1130  const struct bfelf_rela *rela = &(ef->relatab_plt[i]);
1131 
1132  ret = private_relocate_symbol(loader, ef, rela);
1133  if (ret != BFELF_SUCCESS)
1134  {
1135  return ret;
1136  }
1137  }
1138 
1139  return BFELF_SUCCESS;
1140 }
1141 
1142 /* @endcond */
1143 
1144 /* ---------------------------------------------------------------------------------------------- */
1145 /* ELF File Implementation */
1146 /* ---------------------------------------------------------------------------------------------- */
1147 
1148 /* @cond */
1149 
1150 static inline int64_t
1151 private_check_signature(struct bfelf_file_t *ef)
1152 {
1153  if (ef->ehdr->e_ident[bfei_mag0] != 0x7F)
1154  {
1155  return bfinvalid_signature("magic #0 has unexpected value");
1156  }
1157 
1158  if (ef->ehdr->e_ident[bfei_mag1] != 'E')
1159  {
1160  return bfinvalid_signature("magic #1 has unexpected value");
1161  }
1162 
1163  if (ef->ehdr->e_ident[bfei_mag2] != 'L')
1164  {
1165  return bfinvalid_signature("magic #2 has unexpected value");
1166  }
1167 
1168  if (ef->ehdr->e_ident[bfei_mag3] != 'F')
1169  {
1170  return bfinvalid_signature("magic #3 has unexpected value");
1171  }
1172 
1173  return BFELF_SUCCESS;
1174 }
1175 
1176 static inline int64_t
1177 private_check_support(struct bfelf_file_t *ef)
1178 {
1179  if (ef->ehdr->e_ident[bfei_class] != bfelfclass64)
1180  {
1181  return bfunsupported_file("file is not 64bit");
1182  }
1183 
1184  if (ef->ehdr->e_ident[bfei_data] != bfelfdata2lsb)
1185  {
1186  return bfunsupported_file("file is not little endian");
1187  }
1188 
1189  if (ef->ehdr->e_ident[bfei_version] != bfev_current)
1190  {
1191  return bfunsupported_file("unsupported version");
1192  }
1193 
1194  if (ef->ehdr->e_ident[bfei_osabi] != bfelfosabi_sysv)
1195  {
1196  return bfunsupported_file("file does not use the system v abi");
1197  }
1198 
1199  if (ef->ehdr->e_ident[bfei_abiversion] != 0)
1200  {
1201  return bfunsupported_file("unsupported abi version");
1202  }
1203 
1204  if (ef->ehdr->e_type != bfet_dyn && ef->ehdr->e_type != bfet_exec)
1205  {
1206  return bfunsupported_file("file must be an executable or shared library");
1207  }
1208 
1209  if (ef->ehdr->e_machine != bfem_x86_64)
1210  {
1211  return bfunsupported_file("file must be compiled for x86_64");
1212  }
1213 
1214  if (ef->ehdr->e_version != bfev_current)
1215  {
1216  return bfunsupported_file("unsupported version");
1217  }
1218 
1219  if (ef->ehdr->e_flags != 0)
1220  {
1221  return bfunsupported_file("unsupported flags");
1222  }
1223 
1224  return BFELF_SUCCESS;
1225 }
1226 
1227 static inline void
1228 private_process_segments(struct bfelf_file_t *ef)
1229 {
1230  bfelf64_xword i = 0;
1231 
1232  for (i = 0; i < ef->ehdr->e_phnum; i++)
1233  {
1234  const struct bfelf_phdr *phdr = &(ef->phdrtab[i]);
1235 
1236  switch (phdr->p_type)
1237  {
1238  case bfpt_load:
1239 
1240  if (ef->num_loadable_segments < BFELF_MAX_SEGMENTS)
1241  {
1242  ef->total_memsz = phdr->p_vaddr + phdr->p_memsz;
1243  ef->loadable_segments[ef->num_loadable_segments++] = phdr;
1244  }
1245 
1246  break;
1247 
1248  case bfpt_dynamic:
1249  ef->dynoff = phdr->p_offset;
1250  ef->dynnum = phdr->p_filesz / sizeof(struct bfelf_dyn);
1251  break;
1252 
1253  case bfpt_gnu_stack:
1254  ef->stack_flags = phdr->p_flags;
1255  break;
1256 
1257  case bfpt_gnu_relro:
1258  ef->relaro_vaddr = phdr->p_vaddr;
1259  ef->relaro_memsz = phdr->p_memsz;
1260  break;
1261  }
1262  }
1263 
1264  if (ef->num_loadable_segments > 0)
1265  {
1266  ef->start_addr = ef->loadable_segments[0]->p_vaddr;
1267  ef->total_memsz -= ef->start_addr;
1268  }
1269 
1270  for (i = 0; i < ef->num_loadable_segments; i++)
1271  {
1272  const struct bfelf_phdr *phdr = ef->loadable_segments[i];
1273 
1274  ef->load_instr[i].perm = phdr->p_flags;
1275  ef->load_instr[i].mem_offset = phdr->p_vaddr - ef->start_addr;
1276  ef->load_instr[i].file_offset = phdr->p_offset;
1277  ef->load_instr[i].memsz = phdr->p_memsz;
1278  ef->load_instr[i].filesz = phdr->p_filesz;
1279  ef->load_instr[i].virt_addr = phdr->p_vaddr;
1280 
1281  ef->num_load_instr++;
1282  }
1283 }
1284 
1285 static inline void
1286 private_process_dynamic_section(struct bfelf_file_t *ef)
1287 {
1288  bfelf64_xword i = 0;
1289 
1290  if (ef->dynnum == 0 || ef->dynoff == 0)
1291  return;
1292 
1293  ef->num_needed = 0;
1294  ef->dyntab = rcast(const struct bfelf_dyn *, ef->file + ef->dynoff);
1295 
1296  for (i = 0; i < ef->dynnum; i++)
1297  {
1298  const struct bfelf_dyn *dyn = &(ef->dyntab[i]);
1299 
1300  switch (dyn->d_tag)
1301  {
1302  case bfdt_null:
1303  return;
1304 
1305  case bfdt_needed:
1306 
1307  if (ef->num_needed < BFELF_MAX_NEEDED)
1308  {
1309  ef->needed[ef->num_needed++] = dyn->d_val;
1310  }
1311 
1312  break;
1313 
1314  case bfdt_pltrelsz:
1315  ef->relanum_plt = dyn->d_val / sizeof(struct bfelf_rela);
1316  break;
1317 
1318  case bfdt_hash:
1319  ef->hash = rcast(bfelf64_word *, dyn->d_val);
1320  break;
1321 
1322  case bfdt_strtab:
1323  ef->strtab = rcast(char *, dyn->d_val);
1324  break;
1325 
1326  case bfdt_symtab:
1327  ef->symtab = rcast(struct bfelf_sym *, dyn->d_val);
1328  break;
1329 
1330  case bfdt_rela:
1331  ef->relatab_dyn = rcast(struct bfelf_rela *, dyn->d_val);
1332  break;
1333 
1334  case bfdt_relasz:
1335  ef->relanum_dyn = dyn->d_val / sizeof(struct bfelf_rela);
1336  break;
1337 
1338  case bfdt_init:
1339  ef->init = dyn->d_val;
1340  break;
1341 
1342  case bfdt_fini:
1343  ef->fini = dyn->d_val;
1344  break;
1345 
1346  case bfdt_jmprel:
1347  ef->relatab_plt = rcast(struct bfelf_rela *, dyn->d_val);
1348  break;
1349 
1350  case bfdt_init_array:
1351  ef->init_array = dyn->d_val;
1352  break;
1353 
1354  case bfdt_fini_array:
1355  ef->fini_array = dyn->d_val;
1356  break;
1357 
1358  case bfdt_init_arraysz:
1359  ef->init_arraysz = dyn->d_val;
1360  break;
1361 
1362  case bfdt_fini_arraysz:
1363  ef->fini_arraysz = dyn->d_val;
1364  break;
1365 
1366  case bfdt_flags_1:
1367  ef->flags_1 = dyn->d_val;
1368  break;
1369 
1370  default:
1371  break;
1372  }
1373  }
1374 }
1375 
1376 /* @endcond */
1377 
1396 static inline int64_t
1397 bfelf_file_init(const char *file, uint64_t filesz, struct bfelf_file_t *ef)
1398 {
1399  int64_t ret = 0;
1400  bfelf64_word i = 0;
1401 
1402  if (!file)
1403  {
1404  return bfinvalid_argument("file == NULL");
1405  }
1406 
1407  if (!ef)
1408  {
1409  return bfinvalid_argument("ef == NULL");
1410  }
1411 
1412  if (filesz == 0 || filesz < sizeof(struct bfelf_ehdr))
1413  {
1414  return bfinvalid_argument("filesz invalid");
1415  }
1416 
1417  for (i = 0; i < sizeof(struct bfelf_file_t); i++)
1418  {
1419  rcast(char *, ef)[i] = 0;
1420  }
1421 
1422  ef->file = file;
1423  ef->filesz = filesz;
1424 
1425  ef->ehdr = rcast(const struct bfelf_ehdr *, file);
1426  ef->phdrtab = rcast(const struct bfelf_phdr *, file + ef->ehdr->e_phoff);
1427  ef->shdrtab = rcast(const struct bfelf_shdr *, file + ef->ehdr->e_shoff);
1428 
1429  ret = private_check_signature(ef);
1430  if (ret != BFELF_SUCCESS)
1431  {
1432  goto failure;
1433  }
1434 
1435  ret = private_check_support(ef);
1436  if (ret != BFELF_SUCCESS)
1437  {
1438  goto failure;
1439  }
1440 
1441  private_process_segments(ef);
1442  private_process_dynamic_section(ef);
1443 
1444  ef->entry = ef->ehdr->e_entry;
1445  ef->shstrtab = rcast(const char *, file + ef->shdrtab[ef->ehdr->e_shstrndx].sh_offset);
1446 
1447  /*
1448  * ld from binutils 2.27 only has rela.dyn, while ld.gold and ld.lld both
1449  * have rela.dyn and rela.plt. ld from binutils 2.27 also uses
1450  * .init_array / .fini_array instead of .ctors / .dtors, while ld.gold and
1451  * ld.lld still use the old .ctors / .dtors, which do not seems to show
1452  * up in the .dynamic section, so we need to manually search for them.
1453  * Since you will likely only have one or the other, if we see the old
1454  * .ctors / .dtors, we treat it like .init_array / .fini_array for now
1455  * which keeps things simple. Also, ld from binutils 2.27 marks .eh_frame
1456  * with bfsht_x86_64_unwind, while ld.gold and ld.lld both mark .eh_frame
1457  * with bfsht_progbits, also requiring a manual string search.
1458  *
1459  * Note that the file provided in this function is assumed to be deleted
1460  * after this function is called, and thus, we have to search for these
1461  * sections now because the file will not be available later.
1462  */
1463 
1464  for (i = 0; i < ef->ehdr->e_shnum; i++)
1465  {
1466  const struct bfelf_shdr *shdr = &(ef->shdrtab[i]);
1467  const char *name = &ef->shstrtab[shdr->sh_name];
1468 
1469  if (private_strcmp(name, ".eh_frame") == BFELF_SUCCESS)
1470  {
1471  ef->eh_frame = shdr->sh_addr;
1472  ef->eh_framesz = shdr->sh_size;
1473  continue;
1474  }
1475 
1476  if (private_strcmp(name, ".ctors") == BFELF_SUCCESS)
1477  {
1478  ef->init_array = shdr->sh_addr;
1479  ef->init_arraysz = shdr->sh_size;
1480  continue;
1481  }
1482 
1483  if (private_strcmp(name, ".dtors") == BFELF_SUCCESS)
1484  {
1485  ef->fini_array = shdr->sh_addr;
1486  ef->fini_arraysz = shdr->sh_size;
1487  continue;
1488  }
1489  }
1490 
1491  return BFELF_SUCCESS;
1492 
1493 failure:
1494 
1495  for (i = 0; i < sizeof(struct bfelf_file_t); i++)
1496  {
1497  rcast(char *, ef)[i] = 0;
1498  }
1499 
1500  return ret;
1501 }
1502 
1517 static inline int64_t
1518 bfelf_file_get_num_load_instrs(struct bfelf_file_t *ef)
1519 {
1520  if (!ef)
1521  {
1522  return bfinvalid_argument("ef == NULL");
1523  }
1524 
1525  return scast(int64_t, ef->num_load_instr);
1526 }
1527 
1544 static inline int64_t
1545 bfelf_file_get_load_instr(struct bfelf_file_t *ef, uint64_t index, struct bfelf_load_instr **instr)
1546 {
1547  if (!ef)
1548  {
1549  return bfinvalid_argument("ef == NULL");
1550  }
1551 
1552  if (!instr)
1553  {
1554  return bfinvalid_argument("phdr == NULL");
1555  }
1556 
1557  if (index >= ef->num_load_instr)
1558  {
1559  return bfinvalid_index("index >= number of load instructions");
1560  }
1561 
1562  *instr = &(ef->load_instr[index]);
1563  return BFELF_SUCCESS;
1564 }
1565 
1582 static inline int64_t
1583 bfelf_file_get_section_info(struct bfelf_file_t *ef, struct section_info_t *info)
1584 {
1585  bfelf64_word i = 0;
1586 
1587  if (!ef)
1588  {
1589  return bfinvalid_argument("ef == NULL");
1590  }
1591 
1592  if (!info)
1593  {
1594  return bfinvalid_argument("info == NULL");
1595  }
1596 
1597  for (i = 0; i < sizeof(struct section_info_t); i++)
1598  {
1599  rcast(char *, info)[i] = 0;
1600  }
1601 
1602  if (ef->init != 0)
1603  {
1604  info->init_addr = ef->init + ef->exec_virt;
1605  }
1606 
1607  if (ef->fini != 0)
1608  {
1609  info->fini_addr = ef->fini + ef->exec_virt;
1610  }
1611 
1612  if (ef->init_array != 0)
1613  {
1614  info->init_array_addr = ef->init_array + ef->exec_virt;
1615  info->init_array_size = ef->init_arraysz;
1616  }
1617 
1618  if (ef->fini_array != 0)
1619  {
1620  info->fini_array_addr = ef->fini_array + ef->exec_virt;
1621  info->fini_array_size = ef->fini_arraysz;
1622  }
1623 
1624  if (ef->eh_frame != 0)
1625  {
1626  info->eh_frame_addr = ef->eh_frame + ef->exec_virt;
1627  info->eh_frame_size = ef->eh_framesz;
1628  }
1629 
1630  return BFELF_SUCCESS;
1631 }
1632 
1646 static inline int64_t
1647 bfelf_file_get_entry(struct bfelf_file_t *ef, void **addr)
1648 {
1649  if (!ef)
1650  {
1651  return bfinvalid_argument("ef == NULL");
1652  }
1653 
1654  if (!addr)
1655  {
1656  return bfinvalid_argument("addr == NULL");
1657  }
1658 
1659  *addr = rcast(void *, ef->entry + ef->exec_virt);
1660  return BFELF_SUCCESS;
1661 }
1662 
1676 static inline int64_t
1677 bfelf_file_get_stack_perm(struct bfelf_file_t *ef, bfelf64_xword *perm)
1678 {
1679  if (!ef)
1680  {
1681  return bfinvalid_argument("ef == NULL");
1682  }
1683 
1684  if (!perm)
1685  {
1686  return bfinvalid_argument("perm == NULL");
1687  }
1688 
1689  *perm = ef->stack_flags;
1690  return BFELF_SUCCESS;
1691 }
1692 
1709 static inline int64_t
1710 bfelf_file_get_relro(struct bfelf_file_t *ef, bfelf64_addr *addr, bfelf64_xword *size)
1711 {
1712  if (!ef)
1713  {
1714  return bfinvalid_argument("ef == NULL");
1715  }
1716 
1717  if (!addr)
1718  {
1719  return bfinvalid_argument("addr == NULL");
1720  }
1721 
1722  if (!size)
1723  {
1724  return bfinvalid_argument("size == NULL");
1725  }
1726 
1727  *addr = ef->relaro_vaddr + rcast(bfelf64_addr, ef->exec_virt);
1728  *size = ef->relaro_memsz;
1729  return BFELF_SUCCESS;
1730 }
1731 
1744 static inline int64_t
1745 bfelf_file_get_num_needed(struct bfelf_file_t *ef)
1746 {
1747  if (!ef)
1748  {
1749  return bfinvalid_argument("ef == NULL");
1750  }
1751 
1752  return scast(int64_t, ef->num_needed);
1753 }
1754 
1771 static inline int64_t
1772 bfelf_file_get_needed(struct bfelf_file_t *ef, uint64_t index, const char **needed)
1773 {
1774  if (!ef)
1775  {
1776  return bfinvalid_argument("ef == NULL");
1777  }
1778 
1779  if (!needed)
1780  {
1781  return bfinvalid_argument("needed == NULL");
1782  }
1783 
1784  if (index >= ef->num_needed)
1785  {
1786  return bfinvalid_index("index >= number of needed");
1787  }
1788 
1789  *needed = &(ef->strtab[ef->needed[index]]);
1790  return BFELF_SUCCESS;
1791 }
1792 
1805 static inline int64_t
1806 bfelf_file_get_total_size(struct bfelf_file_t *ef)
1807 {
1808  if (!ef)
1809  {
1810  return bfinvalid_argument("ef == NULL");
1811  }
1812 
1813  return scast(int64_t, ef->total_memsz);
1814 }
1815 
1828 static inline int64_t
1829 bfelf_file_get_pic_pie(struct bfelf_file_t *ef)
1830 {
1831  if (!ef)
1832  {
1833  return bfinvalid_argument("ef == NULL");
1834  }
1835 
1836  return ef->start_addr == 0 ? 1 : 0;
1837 }
1838 
1839 /* ---------------------------------------------------------------------------------------------- */
1840 /* ELF Loader Implementation */
1841 /* ---------------------------------------------------------------------------------------------- */
1842 
1861 static inline int64_t
1862 bfelf_loader_add(
1863  struct bfelf_loader_t *loader, struct bfelf_file_t *ef, char *exec_addr, char *exec_virt)
1864 {
1865  bfelf64_addr start;
1866 
1867  if (!loader)
1868  {
1869  return bfinvalid_argument("loader == NULL");
1870  }
1871 
1872  if (!ef)
1873  {
1874  return bfinvalid_argument("ef == NULL");
1875  }
1876 
1877  if (!exec_addr)
1878  {
1879  return bfinvalid_argument("exec_addr == NULL");
1880  }
1881 
1882  if (loader->num >= MAX_NUM_MODULES)
1883  {
1884  return bfloader_full("increase MAX_NUM_MODULES");
1885  }
1886 
1887  if (ef->added++ != 0)
1888  {
1889  return bfinvalid_argument("ef already added");
1890  }
1891 
1892  ef->exec_addr = exec_addr;
1893 
1894  if (ef->start_addr == 0)
1895  {
1896  ef->exec_virt = exec_virt;
1897  }
1898 
1899  start = rcast(bfelf64_addr, ef->exec_addr - ef->start_addr);
1900 
1901  ef->hash = add(const bfelf64_word *, ef->hash, start);
1902  ef->strtab = add(const char *, ef->strtab, start);
1903  ef->symtab = add(const struct bfelf_sym *, ef->symtab, start);
1904  ef->relatab_dyn = add(const struct bfelf_rela *, ef->relatab_dyn, start);
1905  ef->relatab_plt = add(const struct bfelf_rela *, ef->relatab_plt, start);
1906 
1907  ef->nbucket = ef->hash[0];
1908  ef->nchain = ef->hash[1];
1909  ef->bucket = &(ef->hash[2]);
1910  ef->chain = &(ef->hash[2 + ef->nbucket]);
1911 
1912  /*
1913  * Sadly, the only way to determine the total size of the dynamic symbol
1914  * table is to assume that the dynamic string table is always after the
1915  * dynamic symbol table. :(
1916  */
1917  ef->symnum = (rcast(bfelf64_addr, ef->strtab) - rcast(bfelf64_addr, ef->symtab)) /
1918  sizeof(struct bfelf_sym);
1919 
1920  loader->efs[loader->num++] = ef;
1921  return BFELF_SUCCESS;
1922 }
1923 
1937 static inline int64_t
1938 bfelf_loader_relocate(struct bfelf_loader_t *loader)
1939 {
1940  int64_t ret = 0;
1941  bfelf64_word i = 0;
1942 
1943  if (!loader)
1944  {
1945  return bfinvalid_argument("loader == NULL");
1946  }
1947 
1948  if (loader->relocated == 1)
1949  {
1950  return BFELF_SUCCESS;
1951  }
1952 
1953  for (i = 0; i < loader->num; i++)
1954  {
1955  ret = private_relocate_symbols(loader, loader->efs[i]);
1956  if (ret != BFELF_SUCCESS)
1957  {
1958  return ret;
1959  }
1960  }
1961 
1962  loader->relocated = 1;
1963  return BFELF_SUCCESS;
1964 }
1965 
1985 static inline int64_t
1986 bfelf_loader_resolve_symbol(struct bfelf_loader_t *loader, const char *name, void **addr)
1987 {
1988  int64_t ret = 0;
1989 
1990  struct bfelf_file_t *found_ef = 0;
1991  const struct bfelf_sym *found_sym = 0;
1992 
1993  if (!loader)
1994  {
1995  return bfinvalid_argument("loader == NULL");
1996  }
1997 
1998  if (!name)
1999  {
2000  return bfinvalid_argument("name == NULL");
2001  }
2002 
2003  if (!addr)
2004  {
2005  return bfinvalid_argument("addr == NULL");
2006  }
2007 
2008  ret = private_get_sym_global(loader, name, &found_ef, &found_sym);
2009  if (ret != BFELF_SUCCESS)
2010  {
2011  return ret;
2012  }
2013 
2014  *addr = found_ef->exec_virt + found_sym->st_value;
2015  return BFELF_SUCCESS;
2016 }
2017 
2018 #ifdef __cplusplus
2019 }
2020 #endif
2021 
2022 #pragma pack(pop)
2023 #endif
Definition: file.h:35
void * eh_frame_addr
Definition: crt.h:118
#define BFELF_ERROR_NO_SUCH_SYMBOL
Definition: error_codes.h:89
uint64_t fini_array_size
Definition: crt.h:116
bfelf64_off mem_offset
Definition: bfelf_loader.h:210
void * init_addr
Definition: crt.h:109
void * init_array_addr
Definition: crt.h:112
void * fini_addr
Definition: crt.h:110
#define BFELF_ERROR_MISMATCH
Definition: error_codes.h:90
#define MAX_NUM_MODULES
Definition: constants.h:177
bfelf64_off file_offset
Definition: bfelf_loader.h:211
constexpr const auto size
auto index(const T virt, const F from)
constexpr const auto addr
Definition: cpuid_x64.h:80
#define ALERT(...)
Definition: debug.h:156
void * fini_array_addr
Definition: crt.h:115
uint64_t init_array_size
Definition: crt.h:113
#define BFELF_SUCCESS
Definition: error_codes.h:80
bfelf64_addr virt_addr
Definition: bfelf_loader.h:214
constexpr const auto name
Definition: cpuid_x64.h:81
bfelf64_xword filesz
Definition: bfelf_loader.h:213
uint64_t eh_frame_size
Definition: crt.h:119
bfelf64_word perm
Definition: bfelf_loader.h:209
bfelf64_xword memsz
Definition: bfelf_loader.h:212