1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
13 #include "mozilla/CheckedInt.h"
16 #define elfhack_data ".elfhack.data.v" ver
17 #define elfhack_text ".elfhack.text.v" ver
20 # define R_ARM_V4BX 0x28
23 # define R_ARM_CALL 0x1c
26 # define R_ARM_JUMP24 0x1d
28 #ifndef R_ARM_THM_JUMP24
29 # define R_ARM_THM_JUMP24 0x1e
32 char* rundir
= nullptr;
39 class Elf_Addr_Traits
{
41 typedef wrapped
<Elf32_Addr
> Type32
;
42 typedef wrapped
<Elf64_Addr
> Type64
;
44 template <class endian
, typename R
, typename T
>
45 static inline void swap(T
& t
, R
& r
) {
46 r
.value
= endian::swap(t
.value
);
50 typedef serializable
<Elf_Addr_Traits
> Elf_Addr
;
52 class ElfRelHack_Section
: public ElfSection
{
54 ElfRelHack_Section(Elf_Shdr
& s
)
55 : ElfSection(s
, nullptr, nullptr),
56 block_size((8 * s
.sh_entsize
- 1) * s
.sh_entsize
) {
60 void serialize(std::ofstream
& file
, unsigned char ei_class
,
61 unsigned char ei_data
) {
63 relr
.push_back((bitmap
<< 1) | 1);
65 for (std::vector
<Elf64_Addr
>::iterator i
= relr
.begin(); i
!= relr
.end();
69 out
.serialize(file
, ei_class
, ei_data
);
73 bool isRelocatable() { return true; }
75 void push_back(Elf64_Addr offset
) {
76 // The format used for the packed relocations is SHT_RELR, described in
77 // https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ
78 // The gist of it is that an address is recorded, and the following words,
79 // if their LSB is 1, represent a bitmap of word-size-spaced relocations
80 // at the addresses that follow. There can be multiple such bitmaps, such
81 // that very long streaks of (possibly spaced) relocations can be recorded
82 // in a very compact way.
84 // [block_start; block_start + block_size] represents the range of offsets
85 // the current bitmap can record. If the offset doesn't fall in that
86 // range, or if doesn't align properly to be recorded, we record the
87 // bitmap, and slide the block corresponding to a new bitmap. If the
88 // offset doesn't fall in the range for the new bitmap, or if there wasn't
89 // an active bitmap in the first place, we record the offset and start a
90 // new bitmap for the block that follows it.
91 if (!block_start
|| offset
< block_start
||
92 offset
>= block_start
+ block_size
||
93 (offset
- block_start
) % shdr
.sh_entsize
) {
95 relr
.push_back((bitmap
<< 1) | 1);
96 block_start
+= block_size
;
100 relr
.push_back(offset
);
101 block_start
= offset
+ shdr
.sh_entsize
;
104 bitmap
|= 1ULL << ((offset
- block_start
) / shdr
.sh_entsize
);
107 shdr
.sh_size
= (relr
.size() + (bitmap
? 1 : 0)) * shdr
.sh_entsize
;
111 std::vector
<Elf64_Addr
> relr
;
113 Elf64_Addr block_start
= 0;
114 Elf64_Addr bitmap
= 0;
117 class ElfRelHackCode_Section
: public ElfSection
{
119 ElfRelHackCode_Section(Elf_Shdr
& s
, Elf
& e
,
120 ElfRelHack_Section
& relhack_section
, unsigned int init
,
121 unsigned int mprotect_cb
, unsigned int sysconf_cb
)
122 : ElfSection(s
, nullptr, nullptr),
124 relhack_section(relhack_section
),
126 init_trampoline(nullptr),
127 mprotect_cb(mprotect_cb
),
128 sysconf_cb(sysconf_cb
) {
129 std::string
file(rundir
);
131 switch (parent
.getMachine()) {
145 throw std::runtime_error("unsupported architecture");
148 std::ifstream
inject(file
.c_str(), std::ios::in
| std::ios::binary
);
149 elf
= new Elf(inject
);
150 if (elf
->getType() != ET_REL
)
151 throw std::runtime_error("object for injected code is not ET_REL");
152 if (elf
->getMachine() != parent
.getMachine())
153 throw std::runtime_error(
154 "architecture of object for injected code doesn't match");
156 ElfSymtab_Section
* symtab
= nullptr;
158 // Find the symbol table.
159 for (ElfSection
* section
= elf
->getSection(1); section
!= nullptr;
160 section
= section
->getNext()) {
161 if (section
->getType() == SHT_SYMTAB
)
162 symtab
= (ElfSymtab_Section
*)section
;
164 if (symtab
== nullptr)
165 throw std::runtime_error(
166 "Couldn't find a symbol table for the injected code");
168 relro
= parent
.getSegmentByType(PT_GNU_RELRO
);
170 // Find the init symbol
172 std::string symbol
= "init";
173 if (!init
) symbol
+= "_noinit";
174 if (relro
) symbol
+= "_relro";
175 Elf_SymValue
* sym
= symtab
->lookup(symbol
.c_str());
177 throw std::runtime_error(
178 "Couldn't find an 'init' symbol in the injected code");
180 entry_point
= sym
->value
.getValue();
182 // Get all relevant sections from the injected code object.
183 add_code_section(sym
->value
.getSection());
185 // If the original init function is located too far away, we're going to
186 // need to use a trampoline. See comment in inject.c.
187 // Theoretically, we should check for (init - instr) > boundary, where
188 // boundary is the platform-dependent limit, and instr is the virtual
189 // address of the instruction that calls the original init, but we don't
190 // have it at this point, so punt to just init.
191 if ((init
> 0xffffff && parent
.getMachine() == EM_ARM
) ||
192 (init
> 0x07ffffff && parent
.getMachine() == EM_AARCH64
)) {
193 Elf_SymValue
* trampoline
= symtab
->lookup("init_trampoline");
195 throw std::runtime_error(
196 "Couldn't find an 'init_trampoline' symbol in the injected code");
199 init_trampoline
= trampoline
->value
.getSection();
200 add_code_section(init_trampoline
);
203 // Adjust code sections offsets according to their size
204 std::vector
<ElfSection
*>::iterator c
= code
.begin();
205 (*c
)->getShdr().sh_addr
= 0;
206 for (ElfSection
* last
= *(c
++); c
!= code
.end(); ++c
) {
207 unsigned int addr
= last
->getShdr().sh_addr
+ last
->getSize();
208 if (addr
& ((*c
)->getAddrAlign() - 1))
209 addr
= (addr
| ((*c
)->getAddrAlign() - 1)) + 1;
210 (*c
)->getShdr().sh_addr
= addr
;
211 // We need to align this section depending on the greater
212 // alignment required by code sections.
213 if (shdr
.sh_addralign
< (*c
)->getAddrAlign())
214 shdr
.sh_addralign
= (*c
)->getAddrAlign();
217 shdr
.sh_size
= code
.back()->getAddr() + code
.back()->getSize();
218 data
= static_cast<char*>(malloc(shdr
.sh_size
));
220 throw std::runtime_error("Could not malloc ElfSection data");
223 for (c
= code
.begin(); c
!= code
.end(); ++c
) {
224 memcpy(buf
, (*c
)->getData(), (*c
)->getSize());
225 buf
+= (*c
)->getSize();
230 ~ElfRelHackCode_Section() { delete elf
; }
232 void serialize(std::ofstream
& file
, unsigned char ei_class
,
233 unsigned char ei_data
) override
{
234 // Readjust code offsets
235 for (std::vector
<ElfSection
*>::iterator c
= code
.begin(); c
!= code
.end();
237 (*c
)->getShdr().sh_addr
+= getAddr();
240 for (std::vector
<ElfSection
*>::iterator c
= code
.begin(); c
!= code
.end();
242 for (ElfSection
* rel
= elf
->getSection(1); rel
!= nullptr;
243 rel
= rel
->getNext())
244 if (((rel
->getType() == SHT_REL
) || (rel
->getType() == SHT_RELA
)) &&
245 (rel
->getInfo().section
== *c
)) {
246 if (rel
->getType() == SHT_REL
)
247 apply_relocations((ElfRel_Section
<Elf_Rel
>*)rel
, *c
);
249 apply_relocations((ElfRel_Section
<Elf_Rela
>*)rel
, *c
);
253 ElfSection::serialize(file
, ei_class
, ei_data
);
256 bool isRelocatable() override
{ return false; }
258 unsigned int getEntryPoint() { return entry_point
; }
260 void insertBefore(ElfSection
* section
, bool dirty
= true) override
{
261 // Adjust the address so that this section is adjacent to the one it's
262 // being inserted before. This avoids creating holes which subsequently
263 // might lead the PHDR-adjusting code to create unnecessary additional
266 (section
->getAddr() - shdr
.sh_size
) & ~(shdr
.sh_addralign
- 1);
267 ElfSection::insertBefore(section
, dirty
);
271 void add_code_section(ElfSection
* section
) {
273 /* Don't add section if it's already been added in the past */
274 for (auto s
= code
.begin(); s
!= code
.end(); ++s
) {
275 if (section
== *s
) return;
277 code
.push_back(section
);
282 /* Look at the relocations associated to the given section to find other
283 * sections that it requires */
284 void find_code(ElfSection
* section
) {
285 for (ElfSection
* s
= elf
->getSection(1); s
!= nullptr; s
= s
->getNext()) {
286 if (((s
->getType() == SHT_REL
) || (s
->getType() == SHT_RELA
)) &&
287 (s
->getInfo().section
== section
)) {
288 if (s
->getType() == SHT_REL
)
289 scan_relocs_for_code((ElfRel_Section
<Elf_Rel
>*)s
);
291 scan_relocs_for_code((ElfRel_Section
<Elf_Rela
>*)s
);
296 template <typename Rel_Type
>
297 void scan_relocs_for_code(ElfRel_Section
<Rel_Type
>* rel
) {
298 ElfSymtab_Section
* symtab
= (ElfSymtab_Section
*)rel
->getLink();
299 for (auto r
= rel
->rels
.begin(); r
!= rel
->rels
.end(); ++r
) {
300 ElfSection
* section
=
301 symtab
->syms
[ELF64_R_SYM(r
->r_info
)].value
.getSection();
302 add_code_section(section
);
306 // TODO: sort out which non-aarch64 relocation types should be using
307 // `value` (even though in practice it's either 0 or the same as addend)
308 class pc32_relocation
{
310 Elf32_Addr
operator()(unsigned int base_addr
, Elf64_Off offset
,
311 Elf64_Sxword addend
, unsigned int addr
,
313 return addr
+ addend
- offset
- base_addr
;
317 class arm_plt32_relocation
{
319 Elf32_Addr
operator()(unsigned int base_addr
, Elf64_Off offset
,
320 Elf64_Sxword addend
, unsigned int addr
,
322 // We don't care about sign_extend because the only case where this is
323 // going to be used only jumps forward.
324 Elf32_Addr tmp
= (Elf32_Addr
)(addr
- offset
- base_addr
) >> 2;
325 tmp
= (addend
+ tmp
) & 0x00ffffff;
326 return (addend
& 0xff000000) | tmp
;
330 class arm_thm_jump24_relocation
{
332 Elf32_Addr
operator()(unsigned int base_addr
, Elf64_Off offset
,
333 Elf64_Sxword addend
, unsigned int addr
,
335 /* Follows description of b.w and bl instructions as per
336 ARM Architecture Reference Manual ARM® v7-A and ARM® v7-R edition,
337 A8.6.16 We limit ourselves to Encoding T4 of b.w and Encoding T1 of bl.
338 We don't care about sign_extend because the only case where this is
339 going to be used only jumps forward. */
340 Elf32_Addr tmp
= (Elf32_Addr
)(addr
- offset
- base_addr
);
341 unsigned int word0
= addend
& 0xffff, word1
= addend
>> 16;
343 /* Encoding T4 of B.W is 10x1 ; Encoding T1 of BL is 11x1. */
344 unsigned int type
= (word1
& 0xd000) >> 12;
345 if (((word0
& 0xf800) != 0xf000) || ((type
& 0x9) != 0x9))
346 throw std::runtime_error(
347 "R_ARM_THM_JUMP24/R_ARM_THM_CALL relocation only supported for B.W "
348 "<label> and BL <label>");
350 /* When the target address points to ARM code, switch a BL to a
351 * BLX. This however can't be done with a B.W without adding a
352 * trampoline, which is not supported as of now. */
353 if ((addr
& 0x1) == 0) {
355 throw std::runtime_error(
356 "R_ARM_THM_JUMP24/R_ARM_THM_CALL relocation only supported for "
357 "BL <label> when label points to ARM code");
358 /* The address of the target is always relative to a 4-bytes
359 * aligned address, so if the address of the BL instruction is
360 * not 4-bytes aligned, adjust for it. */
361 if ((base_addr
+ offset
) & 0x2) tmp
+= 2;
362 /* Encoding T2 of BLX is 11x0. */
366 unsigned int s
= (word0
& (1 << 10)) >> 10;
367 unsigned int j1
= (word1
& (1 << 13)) >> 13;
368 unsigned int j2
= (word1
& (1 << 11)) >> 11;
369 unsigned int i1
= j1
^ s
? 0 : 1;
370 unsigned int i2
= j2
^ s
? 0 : 1;
372 tmp
+= ((s
<< 24) | (i1
<< 23) | (i2
<< 22) | ((word0
& 0x3ff) << 12) |
373 ((word1
& 0x7ff) << 1));
375 s
= (tmp
& (1 << 24)) >> 24;
376 j1
= ((tmp
& (1 << 23)) >> 23) ^ !s
;
377 j2
= ((tmp
& (1 << 22)) >> 22) ^ !s
;
379 return 0xf000 | (s
<< 10) | ((tmp
& (0x3ff << 12)) >> 12) | (type
<< 28) |
380 (j1
<< 29) | (j2
<< 27) | ((tmp
& 0xffe) << 15);
384 class gotoff_relocation
{
386 Elf32_Addr
operator()(unsigned int base_addr
, Elf64_Off offset
,
387 Elf64_Sxword addend
, unsigned int addr
,
389 return addr
+ addend
;
393 template <int start
, int end
>
394 class abs_lo12_nc_relocation
{
396 Elf32_Addr
operator()(unsigned int base_addr
, Elf64_Off offset
,
397 Elf64_Sxword addend
, unsigned int addr
,
399 // Fill the bits [end:start] of the immediate value in an ADD, LDR or STR
400 // instruction, at bits [21:10].
401 // per ARM® Architecture Reference Manual ARMv8, for ARMv8-A architecture
402 // profile C5.6.4, C5.6.83 or C5.6.178 and ELF for the ARM® 64-bit
403 // Architecture (AArch64) 4.6.6, Table 4-9.
404 Elf64_Word mask
= (1 << (end
+ 1)) - 1;
405 return value
| (((((addr
+ addend
) & mask
) >> start
) & 0xfff) << 10);
409 class adr_prel_pg_hi21_relocation
{
411 Elf32_Addr
operator()(unsigned int base_addr
, Elf64_Off offset
,
412 Elf64_Sxword addend
, unsigned int addr
,
414 // Fill the bits [32:12] of the immediate value in a ADRP instruction,
415 // at bits [23:5]+[30:29].
416 // per ARM® Architecture Reference Manual ARMv8, for ARMv8-A architecture
417 // profile C5.6.10 and ELF for the ARM® 64-bit Architecture
418 // (AArch64) 4.6.6, Table 4-9.
419 Elf64_Word imm
= ((addr
+ addend
) >> 12) - ((base_addr
+ offset
) >> 12);
420 Elf64_Word immLo
= (imm
& 0x3) << 29;
421 Elf64_Word immHi
= (imm
& 0x1ffffc) << 3;
422 return value
& 0x9f00001f | immLo
| immHi
;
426 class call26_relocation
{
428 Elf32_Addr
operator()(unsigned int base_addr
, Elf64_Off offset
,
429 Elf64_Sxword addend
, unsigned int addr
,
431 // Fill the bits [27:2] of the immediate value in a BL instruction,
433 // per ARM® Architecture Reference Manual ARMv8, for ARMv8-A architecture
434 // profile C5.6.26 and ELF for the ARM® 64-bit Architecture
435 // (AArch64) 4.6.6, Table 4-10.
436 return value
| (((addr
+ addend
- offset
- base_addr
) & 0x0ffffffc) >> 2);
440 template <class relocation_type
>
441 void apply_relocation(ElfSection
* the_code
, char* base
, Elf_Rel
* r
,
443 relocation_type relocation
;
445 memcpy(&value
, base
+ r
->r_offset
, 4);
446 value
= relocation(the_code
->getAddr(), r
->r_offset
, value
, addr
, value
);
447 memcpy(base
+ r
->r_offset
, &value
, 4);
450 template <class relocation_type
>
451 void apply_relocation(ElfSection
* the_code
, char* base
, Elf_Rela
* r
,
453 relocation_type relocation
;
455 memcpy(&value
, base
+ r
->r_offset
, 4);
456 Elf32_Addr new_value
=
457 relocation(the_code
->getAddr(), r
->r_offset
, r
->r_addend
, addr
, value
);
458 memcpy(base
+ r
->r_offset
, &new_value
, 4);
461 template <typename Rel_Type
>
462 void apply_relocations(ElfRel_Section
<Rel_Type
>* rel
, ElfSection
* the_code
) {
463 assert(rel
->getType() == Rel_Type::sh_type
);
464 char* buf
= data
+ (the_code
->getAddr() - code
.front()->getAddr());
465 // TODO: various checks on the sections
466 ElfSymtab_Section
* symtab
= (ElfSymtab_Section
*)rel
->getLink();
467 for (typename
std::vector
<Rel_Type
>::iterator r
= rel
->rels
.begin();
468 r
!= rel
->rels
.end(); ++r
) {
469 // TODO: various checks on the symbol
470 const char* name
= symtab
->syms
[ELF64_R_SYM(r
->r_info
)].name
;
472 if (symtab
->syms
[ELF64_R_SYM(r
->r_info
)].value
.getSection() == nullptr) {
473 if (strcmp(name
, "relhack") == 0) {
474 addr
= relhack_section
.getAddr();
475 } else if (strcmp(name
, "relhack_end") == 0) {
476 addr
= relhack_section
.getAddr() + relhack_section
.getSize();
477 } else if (strcmp(name
, "__ehdr_start") == 0) {
478 // TODO: change this ugly hack to something better
479 ElfSection
* ehdr
= parent
.getSection(1)->getPrevious()->getPrevious();
480 addr
= ehdr
->getAddr();
481 } else if (strcmp(name
, "original_init") == 0) {
482 if (init_trampoline
) {
483 addr
= init_trampoline
->getAddr();
487 } else if (strcmp(name
, "real_original_init") == 0) {
489 } else if (relro
&& strcmp(name
, "mprotect_cb") == 0) {
491 } else if (relro
&& strcmp(name
, "sysconf_cb") == 0) {
493 } else if (relro
&& strcmp(name
, "relro_start") == 0) {
494 addr
= relro
->getAddr();
495 } else if (relro
&& strcmp(name
, "relro_end") == 0) {
496 addr
= (relro
->getAddr() + relro
->getMemSize());
497 } else if (strcmp(name
, "_GLOBAL_OFFSET_TABLE_") == 0) {
498 // We actually don't need a GOT, but need it as a reference for
499 // GOTOFF relocations. We'll just use the start of the ELF file
501 } else if (strcmp(name
, "") == 0) {
502 // This is for R_ARM_V4BX, until we find something better
505 throw std::runtime_error("Unsupported symbol in relocation");
508 ElfSection
* section
=
509 symtab
->syms
[ELF64_R_SYM(r
->r_info
)].value
.getSection();
510 assert((section
->getType() == SHT_PROGBITS
) &&
511 (section
->getFlags() & SHF_EXECINSTR
));
512 addr
= symtab
->syms
[ELF64_R_SYM(r
->r_info
)].value
.getValue();
515 #define REL(machine, type) (EM_##machine | (R_##machine##_##type << 8))
516 switch (elf
->getMachine() | (ELF64_R_TYPE(r
->r_info
) << 8)) {
517 case REL(X86_64
, PC32
):
518 case REL(X86_64
, PLT32
):
520 case REL(386, GOTPC
):
521 case REL(ARM
, GOTPC
):
522 case REL(ARM
, REL32
):
523 case REL(AARCH64
, PREL32
):
525 PREL64
): // In theory PREL64 should have its own relocation
526 // function, but in practice it doesn't matter.
527 apply_relocation
<pc32_relocation
>(the_code
, buf
, &*r
, addr
);
530 case REL(ARM
, JUMP24
):
531 case REL(ARM
, PLT32
):
532 apply_relocation
<arm_plt32_relocation
>(the_code
, buf
, &*r
, addr
);
534 case REL(ARM
, THM_PC22
/* THM_CALL */):
535 case REL(ARM
, THM_JUMP24
):
536 apply_relocation
<arm_thm_jump24_relocation
>(the_code
, buf
, &*r
, addr
);
538 case REL(386, GOTOFF
):
539 case REL(ARM
, GOTOFF
):
540 apply_relocation
<gotoff_relocation
>(the_code
, buf
, &*r
, addr
);
542 case REL(AARCH64
, ADD_ABS_LO12_NC
):
543 apply_relocation
<abs_lo12_nc_relocation
<0, 11>>(the_code
, buf
, &*r
,
546 case REL(AARCH64
, ADR_PREL_PG_HI21
):
547 apply_relocation
<adr_prel_pg_hi21_relocation
>(the_code
, buf
, &*r
,
550 case REL(AARCH64
, LDST32_ABS_LO12_NC
):
551 apply_relocation
<abs_lo12_nc_relocation
<2, 11>>(the_code
, buf
, &*r
,
554 case REL(AARCH64
, LDST64_ABS_LO12_NC
):
555 apply_relocation
<abs_lo12_nc_relocation
<3, 11>>(the_code
, buf
, &*r
,
558 case REL(AARCH64
, CALL26
):
559 apply_relocation
<call26_relocation
>(the_code
, buf
, &*r
, addr
);
562 // Ignore R_ARM_V4BX relocations
565 throw std::runtime_error("Unsupported relocation type");
571 ElfRelHack_Section
& relhack_section
;
572 std::vector
<ElfSection
*> code
;
574 ElfSection
* init_trampoline
;
575 unsigned int mprotect_cb
;
576 unsigned int sysconf_cb
;
581 unsigned int get_addend(Elf_Rel
* rel
, Elf
* elf
) {
582 ElfLocation
loc(rel
->r_offset
, elf
);
583 Elf_Addr
addr(loc
.getBuffer(), Elf_Addr::size(elf
->getClass()),
584 elf
->getClass(), elf
->getData());
588 unsigned int get_addend(Elf_Rela
* rel
, Elf
* elf
) { return rel
->r_addend
; }
590 void set_relative_reloc(Elf_Rel
* rel
, Elf
* elf
, unsigned int value
) {
591 ElfLocation
loc(rel
->r_offset
, elf
);
594 addr
.serialize(const_cast<char*>(loc
.getBuffer()),
595 Elf_Addr::size(elf
->getClass()), elf
->getClass(),
599 void set_relative_reloc(Elf_Rela
* rel
, Elf
* elf
, unsigned int value
) {
600 // ld puts the value of relocated relocations both in the addend and
601 // at r_offset. For consistency, keep it that way.
602 set_relative_reloc((Elf_Rel
*)rel
, elf
, value
);
603 rel
->r_addend
= value
;
606 void maybe_split_segment(Elf
* elf
, ElfSegment
* segment
) {
607 std::list
<ElfSection
*>::iterator it
= segment
->begin();
608 for (ElfSection
* last
= *(it
++); it
!= segment
->end(); last
= *(it
++)) {
609 // When two consecutive non-SHT_NOBITS sections are apart by more
610 // than the alignment of the section, the second can be moved closer
611 // to the first, but this requires the segment to be split.
612 if (((*it
)->getType() != SHT_NOBITS
) && (last
->getType() != SHT_NOBITS
) &&
613 ((*it
)->getOffset() - last
->getOffset() - last
->getSize() >
614 segment
->getAlign())) {
615 // Probably very wrong.
617 phdr
.p_type
= PT_LOAD
;
619 phdr
.p_paddr
= phdr
.p_vaddr
+ segment
->getVPDiff();
620 phdr
.p_flags
= segment
->getFlags();
621 phdr
.p_align
= segment
->getAlign();
622 phdr
.p_filesz
= (Elf64_Xword
)-1LL;
623 phdr
.p_memsz
= (Elf64_Xword
)-1LL;
624 ElfSegment
* newSegment
= new ElfSegment(&phdr
);
625 elf
->insertSegmentAfter(segment
, newSegment
);
626 for (; it
!= segment
->end(); ++it
) {
627 newSegment
->addSection(*it
);
629 for (it
= newSegment
->begin(); it
!= newSegment
->end(); ++it
) {
630 segment
->removeSection(*it
);
637 // EH_FRAME constants
638 static const unsigned char DW_EH_PE_absptr
= 0x00;
639 static const unsigned char DW_EH_PE_omit
= 0xff;
642 static const unsigned char DW_EH_PE_LEB128
= 0x01;
643 static const unsigned char DW_EH_PE_data2
= 0x02;
644 static const unsigned char DW_EH_PE_data4
= 0x03;
645 static const unsigned char DW_EH_PE_data8
= 0x04;
648 static const unsigned char DW_EH_PE_signed
= 0x08;
651 static const unsigned char DW_EH_PE_pcrel
= 0x10;
653 // Return the data size part of the encoding value
654 static unsigned char encoding_data_size(unsigned char encoding
) {
655 return encoding
& 0x07;
658 // Advance `step` bytes in the buffer at `data` with size `size`, returning
659 // the advanced buffer pointer and remaining size.
660 // Returns true if step <= size.
661 static bool advance_buffer(char** data
, size_t* size
, size_t step
) {
662 if (step
> *size
) return false;
669 // Advance in the given buffer, skipping the full length of the variable-length
670 // encoded LEB128 type in CIE/FDE data.
671 static bool skip_LEB128(char** data
, size_t* size
) {
672 if (!*size
) return false;
674 while (*size
&& (*(*data
)++ & (char)0x80)) {
680 // Advance in the given buffer, skipping the full length of a pointer encoded
681 // with the given encoding.
682 static bool skip_eh_frame_pointer(char** data
, size_t* size
,
683 unsigned char encoding
) {
684 switch (encoding_data_size(encoding
)) {
686 return advance_buffer(data
, size
, 2);
688 return advance_buffer(data
, size
, 4);
690 return advance_buffer(data
, size
, 8);
691 case DW_EH_PE_LEB128
:
692 return skip_LEB128(data
, size
);
694 throw std::runtime_error("unreachable");
697 // Specialized implementations for adjust_eh_frame_pointer().
698 template <typename T
>
699 static bool adjust_eh_frame_sized_pointer(char** data
, size_t* size
,
700 ElfSection
* eh_frame
,
701 unsigned int origAddr
, Elf
* elf
) {
702 if (*size
< sizeof(T
)) return false;
704 serializable
<FixedSizeData
<T
>> pointer(*data
, *size
, elf
->getClass(),
706 mozilla::CheckedInt
<T
> value
= pointer
.value
;
707 if (origAddr
< eh_frame
->getAddr()) {
708 unsigned int diff
= eh_frame
->getAddr() - origAddr
;
711 unsigned int diff
= origAddr
- eh_frame
->getAddr();
714 if (!value
.isValid())
715 throw std::runtime_error("Overflow while adjusting eh_frame");
716 pointer
.value
= value
.value();
717 pointer
.serialize(*data
, *size
, elf
->getClass(), elf
->getData());
718 return advance_buffer(data
, size
, sizeof(T
));
721 // In the given eh_frame section, adjust the pointer with the given encoding,
722 // pointed to by the given buffer (`data`, `size`), considering the eh_frame
723 // section was originally at `origAddr`. Also advances in the buffer.
724 static bool adjust_eh_frame_pointer(char** data
, size_t* size
,
725 unsigned char encoding
,
726 ElfSection
* eh_frame
, unsigned int origAddr
,
728 if ((encoding
& 0x70) != DW_EH_PE_pcrel
)
729 return skip_eh_frame_pointer(data
, size
, encoding
);
731 if (encoding
& DW_EH_PE_signed
) {
732 switch (encoding_data_size(encoding
)) {
734 return adjust_eh_frame_sized_pointer
<int16_t>(data
, size
, eh_frame
,
737 return adjust_eh_frame_sized_pointer
<int32_t>(data
, size
, eh_frame
,
740 return adjust_eh_frame_sized_pointer
<int64_t>(data
, size
, eh_frame
,
744 switch (encoding_data_size(encoding
)) {
746 return adjust_eh_frame_sized_pointer
<uint16_t>(data
, size
, eh_frame
,
749 return adjust_eh_frame_sized_pointer
<uint32_t>(data
, size
, eh_frame
,
752 return adjust_eh_frame_sized_pointer
<uint64_t>(data
, size
, eh_frame
,
757 throw std::runtime_error("Unsupported eh_frame pointer encoding");
760 // The eh_frame section may contain "PC"-relative pointers. If we move the
761 // section, those need to be adjusted. Other type of pointers are relative to
762 // sections we don't touch.
763 static void adjust_eh_frame(ElfSection
* eh_frame
, unsigned int origAddr
,
765 if (eh_frame
->getAddr() == origAddr
) // nothing to do;
768 char* data
= const_cast<char*>(eh_frame
->getData());
769 size_t size
= eh_frame
->getSize();
770 unsigned char LSDAencoding
= DW_EH_PE_omit
;
771 unsigned char FDEencoding
= DW_EH_PE_absptr
;
774 // Decoding of eh_frame based on https://www.airs.com/blog/archives/460
776 if (size
< sizeof(uint32_t)) goto malformed
;
778 serializable
<FixedSizeData
<uint32_t>> entryLength(
779 data
, size
, elf
->getClass(), elf
->getData());
780 if (!advance_buffer(&data
, &size
, sizeof(uint32_t))) goto malformed
;
783 size_t length
= entryLength
.value
;
789 if (size
< sizeof(uint32_t)) goto malformed
;
791 serializable
<FixedSizeData
<uint32_t>> id(data
, size
, elf
->getClass(),
793 if (!advance_buffer(&cursor
, &length
, sizeof(uint32_t))) goto malformed
;
796 // This is a Common Information Entry
797 if (length
< 2) goto malformed
;
798 // Reset LSDA and FDE encodings, and hasZ for subsequent FDEs.
799 LSDAencoding
= DW_EH_PE_omit
;
800 FDEencoding
= DW_EH_PE_absptr
;
802 // CIE version. Should only be 1 or 3.
803 char version
= *cursor
++;
805 if (version
!= 1 && version
!= 3) {
806 throw std::runtime_error("Unsupported eh_frame version");
808 // NUL terminated string.
809 const char* augmentationString
= cursor
;
810 size_t l
= strnlen(augmentationString
, length
- 1);
811 if (l
== length
- 1) goto malformed
;
812 if (!advance_buffer(&cursor
, &length
, l
+ 1)) goto malformed
;
813 // Skip code alignment factor (LEB128)
814 if (!skip_LEB128(&cursor
, &length
)) goto malformed
;
815 // Skip data alignment factor (LEB128)
816 if (!skip_LEB128(&cursor
, &length
)) goto malformed
;
817 // Skip return address register (single byte in CIE version 1, LEB128
820 if (!advance_buffer(&cursor
, &length
, 1)) goto malformed
;
822 if (!skip_LEB128(&cursor
, &length
)) goto malformed
;
824 // Past this, it's data driven by the contents of the augmentation string.
825 for (size_t i
= 0; i
< l
; i
++) {
826 if (!length
) goto malformed
;
827 switch (augmentationString
[i
]) {
829 if (!skip_LEB128(&cursor
, &length
)) goto malformed
;
833 LSDAencoding
= *cursor
++;
837 FDEencoding
= *cursor
++;
841 unsigned char encoding
= (unsigned char)*cursor
++;
843 if (!adjust_eh_frame_pointer(&cursor
, &length
, encoding
, eh_frame
,
852 // This is a Frame Description Entry
854 if (!adjust_eh_frame_pointer(&cursor
, &length
, FDEencoding
, eh_frame
,
858 if (LSDAencoding
!= DW_EH_PE_omit
) {
859 // Skip number of bytes, same size as the starting address.
860 if (!skip_eh_frame_pointer(&cursor
, &length
, FDEencoding
))
863 if (!skip_LEB128(&cursor
, &length
)) goto malformed
;
865 // pointer to the LSDA.
866 if (!adjust_eh_frame_pointer(&cursor
, &length
, LSDAencoding
, eh_frame
,
872 data
+= entryLength
.value
;
873 size
-= entryLength
.value
;
878 throw std::runtime_error("malformed .eh_frame");
881 template <typename Rel_Type
>
882 int do_relocation_section(Elf
* elf
, unsigned int rel_type
,
883 unsigned int rel_type2
, bool force
) {
884 ElfDynamic_Section
* dyn
= elf
->getDynSection();
885 if (dyn
== nullptr) {
886 fprintf(stderr
, "Couldn't find SHT_DYNAMIC section\n");
890 ElfRel_Section
<Rel_Type
>* section
=
891 (ElfRel_Section
<Rel_Type
>*)dyn
->getSectionForType(Rel_Type::d_tag
);
892 if (section
== nullptr) {
893 fprintf(stderr
, "No relocations\n");
896 assert(section
->getType() == Rel_Type::sh_type
);
898 Elf64_Shdr relhack64_section
= {0,
906 Elf_Addr::size(elf
->getClass()),
907 Elf_Addr::size(elf
->getClass())};
908 Elf64_Shdr relhackcode64_section
= {0,
910 SHF_ALLOC
| SHF_EXECINSTR
,
919 unsigned int entry_sz
= Elf_Addr::size(elf
->getClass());
921 // The injected code needs to be executed before any init code in the
922 // binary. There are three possible cases:
923 // - The binary has no init code at all. In this case, we will add a
924 // DT_INIT entry pointing to the injected code.
925 // - The binary has a DT_INIT entry. In this case, we will interpose:
926 // we change DT_INIT to point to the injected code, and have the
927 // injected code call the original DT_INIT entry point.
928 // - The binary has no DT_INIT entry, but has a DT_INIT_ARRAY. In this
929 // case, we interpose as well, by replacing the first entry in the
930 // array to point to the injected code, and have the injected code
931 // call the original first entry.
932 // The binary may have .ctors instead of DT_INIT_ARRAY, for its init
933 // functions, but this falls into the second case above, since .ctors
934 // are actually run by DT_INIT code.
935 ElfValue
* value
= dyn
->getValueForType(DT_INIT
);
936 unsigned int original_init
= value
? value
->getValue() : 0;
937 ElfSection
* init_array
= nullptr;
938 if (!value
|| !value
->getValue()) {
939 value
= dyn
->getValueForType(DT_INIT_ARRAYSZ
);
940 if (value
&& value
->getValue() >= entry_sz
)
941 init_array
= dyn
->getSectionForType(DT_INIT_ARRAY
);
944 Elf_Shdr
relhack_section(relhack64_section
);
945 Elf_Shdr
relhackcode_section(relhackcode64_section
);
946 auto relhack_ptr
= std::make_unique
<ElfRelHack_Section
>(relhack_section
);
947 auto relhack
= relhack_ptr
.get();
949 ElfSymtab_Section
* symtab
= (ElfSymtab_Section
*)section
->getLink();
950 Elf_SymValue
* sym
= symtab
->lookup("__cxa_pure_virtual");
952 std::vector
<Rel_Type
> new_rels
;
953 std::vector
<Rel_Type
> init_array_relocs
;
954 size_t init_array_insert
= 0;
955 for (typename
std::vector
<Rel_Type
>::iterator i
= section
->rels
.begin();
956 i
!= section
->rels
.end(); ++i
) {
957 // We don't need to keep R_*_NONE relocations
958 if (!ELF64_R_TYPE(i
->r_info
)) continue;
959 ElfLocation
loc(i
->r_offset
, elf
);
960 // __cxa_pure_virtual is a function used in vtables to point at pure
961 // virtual methods. The __cxa_pure_virtual function usually abort()s.
962 // These functions are however normally never called. In the case
963 // where they would, jumping to the null address instead of calling
964 // __cxa_pure_virtual is going to work just as well. So we can remove
965 // relocations for the __cxa_pure_virtual symbol and null out the
966 // content at the offset pointed by the relocation.
969 // If we are statically linked to libstdc++, the
970 // __cxa_pure_virtual symbol is defined in our lib, and we
971 // have relative relocations (rel_type) for it.
972 if (ELF64_R_TYPE(i
->r_info
) == rel_type
) {
973 Elf_Addr
addr(loc
.getBuffer(), entry_sz
, elf
->getClass(),
975 if (addr
.value
== sym
->value
.getValue()) {
976 memset((char*)loc
.getBuffer(), 0, entry_sz
);
981 // If we are dynamically linked to libstdc++, the
982 // __cxa_pure_virtual symbol is undefined in our lib, and we
983 // have absolute relocations (rel_type2) for it.
984 if ((ELF64_R_TYPE(i
->r_info
) == rel_type2
) &&
985 (sym
== &symtab
->syms
[ELF64_R_SYM(i
->r_info
)])) {
986 memset((char*)loc
.getBuffer(), 0, entry_sz
);
991 // Keep track of the relocations associated with the init_array section.
992 if (init_array
&& i
->r_offset
>= init_array
->getAddr() &&
993 i
->r_offset
< init_array
->getAddr() + init_array
->getSize()) {
994 init_array_relocs
.push_back(*i
);
995 init_array_insert
= new_rels
.size();
996 } else if (!(loc
.getSection()->getFlags() & SHF_WRITE
) ||
997 (ELF64_R_TYPE(i
->r_info
) != rel_type
)) {
998 // Don't pack relocations happening in non writable sections.
999 // Our injected code is likely not to be allowed to write there.
1000 new_rels
.push_back(*i
);
1001 } else if (i
->r_offset
& 1) {
1002 // RELR packing doesn't support relocations at an odd address, but
1003 // there shouldn't be any.
1004 new_rels
.push_back(*i
);
1006 // With Elf_Rel, the value pointed by the relocation offset is the addend.
1007 // With Elf_Rela, the addend is in the relocation entry, but the elfhacked
1008 // relocation info doesn't contain it. Elfhack relies on the value pointed
1009 // by the relocation offset to also contain the addend. Which is true with
1010 // BFD ld and gold, but not lld, which leaves that nulled out. So if that
1011 // value is nulled out, we update it to the addend.
1012 Elf_Addr
addr(loc
.getBuffer(), entry_sz
, elf
->getClass(), elf
->getData());
1013 unsigned int addend
= get_addend(&*i
, elf
);
1014 if (addr
.value
== 0) {
1015 addr
.value
= addend
;
1016 addr
.serialize(const_cast<char*>(loc
.getBuffer()), entry_sz
,
1017 elf
->getClass(), elf
->getData());
1018 } else if (addr
.value
!= addend
) {
1020 "Relocation addend inconsistent with content. Skipping\n");
1023 relhack
->push_back(i
->r_offset
);
1028 // Some linkers create a DT_INIT_ARRAY section that, for all purposes,
1029 // is empty: it only contains 0x0 or 0xffffffff pointers with no
1030 // relocations. In some other cases, there can be null pointers with no
1031 // relocations in the middle of the section. Example: crtend_so.o in the
1032 // Android NDK contains a sized .init_array with a null pointer and no
1033 // relocation, which ends up in all Android libraries, and in some cases it
1034 // ends up in the middle of the final .init_array section. If we have such a
1035 // reusable slot at the beginning of .init_array, we just use it. It we have
1036 // one in the middle of .init_array, we slide its content to move the "hole"
1037 // at the beginning and use it there (we need our injected code to run
1038 // before any other). Otherwise, replace the first entry and keep the
1039 // original pointer.
1040 std::sort(init_array_relocs
.begin(), init_array_relocs
.end(),
1041 [](Rel_Type
& a
, Rel_Type
& b
) { return a
.r_offset
< b
.r_offset
; });
1042 size_t expected
= init_array
->getAddr();
1043 const size_t zero
= 0;
1044 const size_t all
= SIZE_MAX
;
1045 const char* data
= init_array
->getData();
1046 size_t length
= Elf_Addr::size(elf
->getClass());
1048 for (; off
< init_array_relocs
.size(); off
++) {
1049 auto& r
= init_array_relocs
[off
];
1050 if (r
.r_offset
>= expected
+ length
&&
1051 (memcmp(data
+ off
* length
, &zero
, length
) == 0 ||
1052 memcmp(data
+ off
* length
, &all
, length
) == 0)) {
1053 // We found a hole, move the preceding entries.
1055 auto& p
= init_array_relocs
[--off
];
1056 if (ELF64_R_TYPE(p
.r_info
) == rel_type
) {
1057 unsigned int addend
= get_addend(&p
, elf
);
1058 p
.r_offset
+= length
;
1059 set_relative_reloc(&p
, elf
, addend
);
1062 "Unsupported relocation type in DT_INIT_ARRAY. Skipping\n");
1068 expected
= r
.r_offset
+ length
;
1072 // We either found a hole above, and can now use the first entry,
1073 // or the init_array section is effectively empty (see further above)
1074 // and we also can use the first entry.
1075 // Either way, code further below will take care of actually setting
1076 // the right r_info and r_added for the relocation.
1078 rel
.r_offset
= init_array
->getAddr();
1079 init_array_relocs
.insert(init_array_relocs
.begin(), rel
);
1081 // Use relocated value of DT_INIT_ARRAY's first entry for the
1082 // function to be called by the injected code.
1083 auto& rel
= init_array_relocs
[0];
1084 unsigned int addend
= get_addend(&rel
, elf
);
1085 if (ELF64_R_TYPE(rel
.r_info
) == rel_type
) {
1086 original_init
= addend
;
1087 } else if (ELF64_R_TYPE(rel
.r_info
) == rel_type2
) {
1088 ElfSymtab_Section
* symtab
= (ElfSymtab_Section
*)section
->getLink();
1090 symtab
->syms
[ELF64_R_SYM(rel
.r_info
)].value
.getValue() + addend
;
1093 "Unsupported relocation type for DT_INIT_ARRAY's first entry. "
1099 new_rels
.insert(std::next(new_rels
.begin(), init_array_insert
),
1100 init_array_relocs
.begin(), init_array_relocs
.end());
1103 unsigned int mprotect_cb
= 0;
1104 unsigned int sysconf_cb
= 0;
1105 // If there is a relro segment, our injected code will run after the linker
1106 // sets the corresponding pages read-only. We need to make our code change
1107 // that to read-write before applying relocations, which means it needs to
1108 // call mprotect. To do that, we need to find a reference to the mprotect
1109 // symbol. In case the library already has one, we use that, but otherwise, we
1110 // add the symbol. Then the injected code needs to be able to call the
1111 // corresponding function, which means it needs access to a pointer to it. We
1112 // get such a pointer by making the linker apply a relocation for the symbol
1113 // at an address our code can read. The problem here is that there is not much
1114 // relocated space where we can put such a pointer, so we abuse the bss
1115 // section temporarily (it will be restored to a null value before any code
1116 // can actually use it)
1117 if (elf
->getSegmentByType(PT_GNU_RELRO
)) {
1118 ElfSection
* gnu_versym
= dyn
->getSectionForType(DT_VERSYM
);
1119 auto lookup
= [&symtab
, &gnu_versym
](const char* symbol
) {
1120 Elf_SymValue
* sym_value
= symtab
->lookup(symbol
, STT(FUNC
));
1122 symtab
->syms
.emplace_back();
1123 sym_value
= &symtab
->syms
.back();
1124 symtab
->grow(symtab
->syms
.size() * symtab
->getEntSize());
1126 ((ElfStrtab_Section
*)symtab
->getLink())->getStr(symbol
);
1127 sym_value
->info
= ELF64_ST_INFO(STB_GLOBAL
, STT_FUNC
);
1128 sym_value
->other
= STV_DEFAULT
;
1129 new (&sym_value
->value
) ElfLocation(nullptr, 0, ElfLocation::ABSOLUTE
);
1130 sym_value
->size
= 0;
1131 sym_value
->defined
= false;
1133 // The DT_VERSYM data (in the .gnu.version section) has the same number
1134 // of entries as the symbols table. Since we added one entry there, we
1135 // need to add one entry here. Zeroes in the extra data means no version
1136 // for that symbol, which is the simplest thing to do.
1138 gnu_versym
->grow(gnu_versym
->getSize() + gnu_versym
->getEntSize());
1144 Elf_SymValue
* mprotect
= lookup("mprotect");
1145 Elf_SymValue
* sysconf
= lookup("sysconf");
1147 // Add relocations for the mprotect and sysconf symbols.
1148 auto add_relocation_to
= [&new_rels
, &symtab
, rel_type2
](
1149 Elf_SymValue
* symbol
, unsigned int location
) {
1150 new_rels
.emplace_back();
1151 Rel_Type
& rel
= new_rels
.back();
1152 memset(&rel
, 0, sizeof(rel
));
1153 rel
.r_info
= ELF64_R_INFO(
1154 std::distance(symtab
->syms
.begin(),
1155 std::vector
<Elf_SymValue
>::iterator(symbol
)),
1157 rel
.r_offset
= location
;
1161 // Find the beginning of the bss section, and use an aligned location in
1162 // there for the relocation.
1163 for (ElfSection
* s
= elf
->getSection(1); s
!= nullptr; s
= s
->getNext()) {
1164 if (s
->getType() != SHT_NOBITS
||
1165 (s
->getFlags() & (SHF_TLS
| SHF_WRITE
)) != SHF_WRITE
) {
1168 size_t ptr_size
= Elf_Addr::size(elf
->getClass());
1169 size_t usable_start
= (s
->getAddr() + ptr_size
- 1) & ~(ptr_size
- 1);
1170 size_t usable_end
= (s
->getAddr() + s
->getSize()) & ~(ptr_size
- 1);
1171 if (usable_end
- usable_start
>= 2 * ptr_size
) {
1172 mprotect_cb
= add_relocation_to(mprotect
, usable_start
);
1173 sysconf_cb
= add_relocation_to(sysconf
, usable_start
+ ptr_size
);
1178 if (mprotect_cb
== 0 || sysconf_cb
== 0) {
1179 fprintf(stderr
, "Couldn't find .bss. Skipping\n");
1184 size_t old_size
= section
->getSize();
1186 section
->rels
.assign(new_rels
.begin(), new_rels
.end());
1187 section
->shrink(new_rels
.size() * section
->getEntSize());
1189 auto relhackcode_ptr
= std::make_unique
<ElfRelHackCode_Section
>(
1190 relhackcode_section
, *elf
, *relhack
, original_init
, mprotect_cb
,
1192 auto relhackcode
= relhackcode_ptr
.get();
1193 // Find the first executable section, and insert the relhack code before
1194 // that. The relhack data is inserted between .rel.dyn and .rel.plt.
1195 ElfSection
* first_executable
= nullptr;
1196 for (ElfSection
* s
= elf
->getSection(1); s
!= nullptr; s
= s
->getNext()) {
1197 if (s
->getFlags() & SHF_EXECINSTR
) {
1198 first_executable
= s
;
1203 if (!first_executable
) {
1204 fprintf(stderr
, "Couldn't find executable section. Skipping\n");
1208 // Once the pointers for relhack, relhackcode, and init are inserted,
1209 // their ownership is transferred to the Elf object, which will free
1210 // them when itself is freed. Hence the .release() calls here (and
1211 // the init.release() call later on). Please note that the raw
1212 // pointers will continue to be used after .release(), which is why
1213 // we are caching them (since .release() will end up setting the
1214 // smart pointer's internal raw pointer to nullptr).
1216 relhack
->insertBefore(section
);
1217 relhack_ptr
.release();
1219 relhackcode
->insertBefore(first_executable
);
1220 relhackcode_ptr
.release();
1222 // Don't try further if we can't gain from the relocation section size change.
1223 // We account for the fact we're going to split the PT_LOAD before the
1224 // injected code section, so the overhead of the page alignment for section
1225 // needs to be accounted for.
1226 size_t align
= first_executable
->getSegmentByType(PT_LOAD
)->getAlign();
1227 size_t new_size
= relhack
->getSize() + section
->getSize() +
1228 relhackcode
->getSize() +
1229 (relhackcode
->getAddr() & (align
- 1));
1230 if (!force
&& (new_size
>= old_size
|| old_size
- new_size
< align
)) {
1231 fprintf(stderr
, "No gain. Skipping\n");
1235 // .eh_frame/.eh_frame_hdr may be between the relocation sections and the
1236 // executable sections. When that happens, we may end up creating a separate
1237 // PT_LOAD for just both of them because they are not considered relocatable.
1238 // But they are, in fact, kind of relocatable, albeit with some manual work.
1239 // Which we'll do here.
1240 ElfSegment
* eh_frame_segment
= elf
->getSegmentByType(PT_GNU_EH_FRAME
);
1241 ElfSection
* eh_frame_hdr
=
1242 eh_frame_segment
? eh_frame_segment
->getFirstSection() : nullptr;
1243 // The .eh_frame section usually follows the eh_frame_hdr section.
1244 ElfSection
* eh_frame
= eh_frame_hdr
? eh_frame_hdr
->getNext() : nullptr;
1245 ElfSection
* first
= eh_frame_hdr
;
1246 ElfSection
* second
= eh_frame
;
1247 if (eh_frame
&& strcmp(eh_frame
->getName(), ".eh_frame")) {
1248 // But sometimes it appears *before* the eh_frame_hdr section.
1249 eh_frame
= eh_frame_hdr
->getPrevious();
1251 second
= eh_frame_hdr
;
1253 if (eh_frame_hdr
&& (!eh_frame
|| strcmp(eh_frame
->getName(), ".eh_frame"))) {
1254 throw std::runtime_error(
1255 "Expected to find an .eh_frame section adjacent to .eh_frame_hdr");
1257 if (eh_frame
&& first
->getAddr() > relhack
->getAddr() &&
1258 second
->getAddr() < first_executable
->getAddr()) {
1259 // The distance between both sections needs to be preserved because
1260 // eh_frame_hdr contains relative offsets to eh_frame. Well, they could be
1261 // relocated too, but it's not worth the effort for the few number of bytes
1263 Elf64_Off distance
= second
->getAddr() - first
->getAddr();
1264 Elf64_Addr origAddr
= eh_frame
->getAddr();
1265 ElfSection
* previous
= first
->getPrevious();
1266 first
->getShdr().sh_addr
= (previous
->getAddr() + previous
->getSize() +
1267 first
->getAddrAlign() - 1) &
1268 ~(first
->getAddrAlign() - 1);
1269 second
->getShdr().sh_addr
=
1270 (first
->getAddr() + std::min(first
->getSize(), distance
) +
1271 second
->getAddrAlign() - 1) &
1272 ~(second
->getAddrAlign() - 1);
1273 // Re-adjust to keep the original distance.
1274 // If the first section has a smaller alignment requirement than the second,
1275 // the second will be farther away, so we need to adjust the first.
1276 // If the second section has a smaller alignment requirement than the first,
1277 // it will already be at the right distance.
1278 first
->getShdr().sh_addr
= second
->getAddr() - distance
;
1279 assert(distance
== second
->getAddr() - first
->getAddr());
1281 adjust_eh_frame(eh_frame
, origAddr
, elf
);
1284 // Adjust PT_LOAD segments
1285 for (ElfSegment
* segment
= elf
->getSegmentByType(PT_LOAD
); segment
;
1286 segment
= elf
->getSegmentByType(PT_LOAD
, segment
)) {
1287 maybe_split_segment(elf
, segment
);
1290 // Ensure Elf sections will be at their final location.
1293 std::make_unique
<ElfLocation
>(relhackcode
, relhackcode
->getEntryPoint());
1295 // Adjust the first DT_INIT_ARRAY entry to point at the injected code
1296 // by transforming its relocation into a relative one pointing to the
1297 // address of the injected code.
1298 Rel_Type
* rel
= §ion
->rels
[init_array_insert
];
1299 rel
->r_info
= ELF64_R_INFO(0, rel_type
); // Set as a relative relocation
1300 set_relative_reloc(rel
, elf
, init
->getValue());
1302 if (dyn
->setValueForType(DT_INIT
, init
.get())) {
1305 fprintf(stderr
, "Can't grow .dynamic section to set DT_INIT. Skipping\n");
1310 // TODO: adjust the value according to the remaining number of relative
1312 if (dyn
->getValueForType(Rel_Type::d_tag_count
))
1313 dyn
->setValueForType(Rel_Type::d_tag_count
, new ElfPlainValue(0));
1318 static inline int backup_file(const char* name
) {
1319 std::string
fname(name
);
1321 return rename(name
, fname
.c_str());
1324 void do_file(const char* name
, bool backup
= false, bool force
= false) {
1325 std::ifstream
file(name
, std::ios::in
| std::ios::binary
);
1327 unsigned int size
= elf
.getSize();
1328 fprintf(stderr
, "%s: ", name
);
1329 if (elf
.getType() != ET_DYN
) {
1330 fprintf(stderr
, "Not a shared object. Skipping\n");
1334 for (ElfSection
* section
= elf
.getSection(1); section
!= nullptr;
1335 section
= section
->getNext()) {
1336 if (section
->getName() &&
1337 (strncmp(section
->getName(), ".elfhack.", 9) == 0)) {
1338 fprintf(stderr
, "Already elfhacked. Skipping\n");
1344 switch (elf
.getMachine()) {
1347 do_relocation_section
<Elf_Rel
>(&elf
, R_386_RELATIVE
, R_386_32
, force
);
1350 exit
= do_relocation_section
<Elf_Rela
>(&elf
, R_X86_64_RELATIVE
,
1351 R_X86_64_64
, force
);
1354 exit
= do_relocation_section
<Elf_Rel
>(&elf
, R_ARM_RELATIVE
, R_ARM_ABS32
,
1358 exit
= do_relocation_section
<Elf_Rela
>(&elf
, R_AARCH64_RELATIVE
,
1359 R_AARCH64_ABS64
, force
);
1362 throw std::runtime_error("unsupported architecture");
1365 if (!force
&& (elf
.getSize() >= size
)) {
1366 fprintf(stderr
, "No gain. Skipping\n");
1367 } else if (backup
&& backup_file(name
) != 0) {
1368 fprintf(stderr
, "Couln't create backup file\n");
1370 std::ofstream
ofile(name
,
1371 std::ios::out
| std::ios::binary
| std::ios::trunc
);
1373 fprintf(stderr
, "Reduced by %d bytes\n", size
- elf
.getSize());
1378 void undo_file(const char* name
, bool backup
= false) {
1379 std::ifstream
file(name
, std::ios::in
| std::ios::binary
);
1381 unsigned int size
= elf
.getSize();
1382 fprintf(stderr
, "%s: ", name
);
1383 if (elf
.getType() != ET_DYN
) {
1384 fprintf(stderr
, "Not a shared object. Skipping\n");
1388 ElfSection
*data
= nullptr, *text
= nullptr;
1389 for (ElfSection
* section
= elf
.getSection(1); section
!= nullptr;
1390 section
= section
->getNext()) {
1391 if (section
->getName() && (strcmp(section
->getName(), elfhack_data
) == 0))
1393 if (section
->getName() && (strcmp(section
->getName(), elfhack_text
) == 0))
1397 if (!data
|| !text
) {
1398 fprintf(stderr
, "Not elfhacked. Skipping\n");
1402 // When both elfhack sections are in the same segment, try to merge
1403 // the segment that contains them both and the following segment.
1404 // When the elfhack sections are in separate segments, try to merge
1406 ElfSegment
* first
= data
->getSegmentByType(PT_LOAD
);
1407 ElfSegment
* second
= text
->getSegmentByType(PT_LOAD
);
1408 if (first
== second
) {
1409 second
= elf
.getSegmentByType(PT_LOAD
, first
);
1412 // Only merge the segments when their flags match.
1413 if (second
->getFlags() != first
->getFlags()) {
1414 fprintf(stderr
, "Couldn't merge PT_LOAD segments. Skipping\n");
1417 // Move sections from the second PT_LOAD to the first, and remove the
1418 // second PT_LOAD segment.
1419 for (std::list
<ElfSection
*>::iterator section
= second
->begin();
1420 section
!= second
->end(); ++section
)
1421 first
->addSection(*section
);
1423 elf
.removeSegment(second
);
1426 if (backup
&& backup_file(name
) != 0) {
1427 fprintf(stderr
, "Couln't create backup file\n");
1429 std::ofstream
ofile(name
,
1430 std::ios::out
| std::ios::binary
| std::ios::trunc
);
1432 fprintf(stderr
, "Grown by %d bytes\n", elf
.getSize() - size
);
1436 int main(int argc
, char* argv
[]) {
1438 bool backup
= false;
1440 bool revert
= false;
1441 char* lastSlash
= rindex(argv
[0], '/');
1442 if (lastSlash
!= nullptr) rundir
= strndup(argv
[0], lastSlash
- argv
[0]);
1443 for (arg
= 1; arg
< argc
; arg
++) {
1444 if (strcmp(argv
[arg
], "-f") == 0)
1446 else if (strcmp(argv
[arg
], "-b") == 0)
1448 else if (strcmp(argv
[arg
], "-r") == 0)
1451 undo_file(argv
[arg
], backup
);
1453 do_file(argv
[arg
], backup
, force
);