Bug 1388713 - Change how elfhack looks for the bss section. r?froydnj
In
bug 635961, elfhack was made to (ab)use the bss section as a
temporary space for a pointer. To find it, it scanned writable PT_LOAD
segments to find one that has a different file and memory size,
indicating the presence of .bss. This usually works fine, but when
the binary is linked with lld and relro is enabled, the end of the
file-backed part of the PT_LOAD segment containing the .bss section
ends up in the RELRO segment, making that location read-only and
subsequently making the elfhacked binary crash when it tries to restore
the .bss to a clean state, because it's not actually writing in the .bss
section: lld page aligns it after the RELRO segment.
So instead of scanning PT_LOAD segments, we scan for SHT_NOBITS
sections that are not SHF_TLS (i.e. not .tbss).
--- a/build/unix/elfhack/elfhack.cpp
+++ b/build/unix/elfhack/elfhack.cpp
@@ -724,25 +724,25 @@ int do_relocation_section(Elf *elf, unsi
// Add a relocation for the mprotect symbol.
new_rels.emplace_back();
Rel_Type &rel = new_rels.back();
memset(&rel, 0, sizeof(rel));
rel.r_info = ELF32_R_INFO(std::distance(symtab->syms.begin(), std::vector<Elf_SymValue>::iterator(mprotect)), rel_type2);
// Find the beginning of the bss section, and use an aligned location in there
// for the relocation.
- for (ElfSegment *segment = elf->getSegmentByType(PT_LOAD); segment;
- segment = elf->getSegmentByType(PT_LOAD, segment)) {
- if ((segment->getFlags() & PF_W) == 0)
+ for (ElfSection *s = elf->getSection(1); s != nullptr; s = s->getNext()) {
+ if (s->getType() != SHT_NOBITS || (s->getFlags() & (SHF_TLS | SHF_WRITE)) != SHF_WRITE) {
continue;
+ }
size_t ptr_size = Elf_Addr::size(elf->getClass());
- size_t aligned_mem_end = (segment->getAddr() + segment->getMemSize() + ptr_size - 1) & ~(ptr_size - 1);
- size_t aligned_file_end = (segment->getAddr() + segment->getFileSize() + ptr_size - 1) & ~(ptr_size - 1);
- if (aligned_mem_end - aligned_file_end >= Elf_Addr::size(elf->getClass())) {
- mprotect_cb = rel.r_offset = aligned_file_end;
+ size_t usable_start = (s->getAddr() + ptr_size - 1) & ~(ptr_size - 1);
+ size_t usable_end = (s->getAddr() + s->getSize()) & ~(ptr_size - 1);
+ if (usable_end - usable_start >= ptr_size) {
+ mprotect_cb = rel.r_offset = usable_start;
break;
}
}
if (mprotect_cb == 0) {
fprintf(stderr, "Couldn't find .bss. Skipping\n");
return -1;
}