Bug 1388713 - Change how elfhack looks for the bss section. r?froydnj draft
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 10 Aug 2017 07:55:55 +0900
changeset 643609 99c8b4b1e1afc53c42dc1043a979e0c051aeca86
parent 643608 ee93e0ee55df3d2185120ff116850c397b56ce48
child 725348 ea6db378d7b7b634a36aea23bb1b683436490240
push id73149
push userbmo:mh+mozilla@glandium.org
push dateWed, 09 Aug 2017 23:08:05 +0000
reviewersfroydnj
bugs1388713, 635961
milestone57.0a1
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).
build/unix/elfhack/elfhack.cpp
--- 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;
         }