build/unix/elfhack/elf.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     5 #undef NDEBUG
     6 #include <cstring>
     7 #include <assert.h>
     8 #include "elfxx.h"
    10 template <class endian, typename R, typename T>
    11 void Elf_Ehdr_Traits::swap(T &t, R &r)
    12 {
    13     memcpy(r.e_ident, t.e_ident, sizeof(r.e_ident));
    14     r.e_type = endian::swap(t.e_type);
    15     r.e_machine = endian::swap(t.e_machine);
    16     r.e_version = endian::swap(t.e_version);
    17     r.e_entry = endian::swap(t.e_entry);
    18     r.e_phoff = endian::swap(t.e_phoff);
    19     r.e_shoff = endian::swap(t.e_shoff);
    20     r.e_flags = endian::swap(t.e_flags);
    21     r.e_ehsize = endian::swap(t.e_ehsize);
    22     r.e_phentsize = endian::swap(t.e_phentsize);
    23     r.e_phnum = endian::swap(t.e_phnum);
    24     r.e_shentsize = endian::swap(t.e_shentsize);
    25     r.e_shnum = endian::swap(t.e_shnum);
    26     r.e_shstrndx = endian::swap(t.e_shstrndx);
    27 }
    29 template <class endian, typename R, typename T>
    30 void Elf_Phdr_Traits::swap(T &t, R &r)
    31 {
    32     r.p_type = endian::swap(t.p_type);
    33     r.p_offset = endian::swap(t.p_offset);
    34     r.p_vaddr = endian::swap(t.p_vaddr);
    35     r.p_paddr = endian::swap(t.p_paddr);
    36     r.p_filesz = endian::swap(t.p_filesz);
    37     r.p_memsz = endian::swap(t.p_memsz);
    38     r.p_flags = endian::swap(t.p_flags);
    39     r.p_align = endian::swap(t.p_align);
    40 }
    42 template <class endian, typename R, typename T>
    43 void Elf_Shdr_Traits::swap(T &t, R &r)
    44 {
    45     r.sh_name = endian::swap(t.sh_name);
    46     r.sh_type = endian::swap(t.sh_type);
    47     r.sh_flags = endian::swap(t.sh_flags);
    48     r.sh_addr = endian::swap(t.sh_addr);
    49     r.sh_offset = endian::swap(t.sh_offset);
    50     r.sh_size = endian::swap(t.sh_size);
    51     r.sh_link = endian::swap(t.sh_link);
    52     r.sh_info = endian::swap(t.sh_info);
    53     r.sh_addralign = endian::swap(t.sh_addralign);
    54     r.sh_entsize = endian::swap(t.sh_entsize);
    55 }
    57 template <class endian, typename R, typename T>
    58 void Elf_Dyn_Traits::swap(T &t, R &r)
    59 {
    60     r.d_tag = endian::swap(t.d_tag);
    61     r.d_un.d_val = endian::swap(t.d_un.d_val);
    62 }
    64 template <class endian, typename R, typename T>
    65 void Elf_Sym_Traits::swap(T &t, R &r)
    66 {
    67     r.st_name = endian::swap(t.st_name);
    68     r.st_value = endian::swap(t.st_value);
    69     r.st_size = endian::swap(t.st_size);
    70     r.st_info = t.st_info;
    71     r.st_other = t.st_other;
    72     r.st_shndx = endian::swap(t.st_shndx);
    73 }
    75 template <class endian>
    76 struct _Rel_info {
    77     static inline void swap(Elf32_Word &t, Elf32_Word &r) { r = endian::swap(t); }
    78     static inline void swap(Elf64_Xword &t, Elf64_Xword &r) { r = endian::swap(t); }
    79     static inline void swap(Elf64_Xword &t, Elf32_Word &r) {
    80         r = endian::swap(ELF32_R_INFO(ELF64_R_SYM(t), ELF64_R_TYPE(t)));
    81     }
    82     static inline void swap(Elf32_Word &t, Elf64_Xword &r) {
    83         r = endian::swap(ELF64_R_INFO(ELF32_R_SYM(t), ELF32_R_TYPE(t)));
    84     }
    85 };
    87 template <class endian, typename R, typename T>
    88 void Elf_Rel_Traits::swap(T &t, R &r)
    89 {
    90     r.r_offset = endian::swap(t.r_offset);
    91     _Rel_info<endian>::swap(t.r_info, r.r_info);
    92 }
    94 template <class endian, typename R, typename T>
    95 void Elf_Rela_Traits::swap(T &t, R &r)
    96 {
    97     r.r_offset = endian::swap(t.r_offset);
    98     _Rel_info<endian>::swap(t.r_info, r.r_info);
    99     r.r_addend = endian::swap(t.r_addend);
   100 }
   102 static const Elf32_Shdr null32_section =
   103     { 0, SHT_NULL, 0, 0, 0, 0, SHN_UNDEF, 0, 0, 0 };
   105 Elf_Shdr null_section(null32_section);
   107 Elf_Ehdr::Elf_Ehdr(std::ifstream &file, char ei_class, char ei_data)
   108 : serializable<Elf_Ehdr_Traits>(file, ei_class, ei_data),
   109   ElfSection(null_section, nullptr, nullptr)
   110 {
   111     shdr.sh_size = Elf_Ehdr::size(ei_class);
   112 }
   114 Elf::Elf(std::ifstream &file)
   115 {
   116     if (!file.is_open())
   117         throw std::runtime_error("Error opening file");
   119     file.exceptions(std::ifstream::eofbit | std::ifstream::failbit | std::ifstream::badbit);
   120     // Read ELF magic number and identification information
   121     char e_ident[EI_VERSION];
   122     file.seekg(0);
   123     file.read(e_ident, sizeof(e_ident));
   124     file.seekg(0);
   125     ehdr = new Elf_Ehdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
   127     // ELFOSABI_LINUX is kept unsupported because I haven't looked whether
   128     // STB_GNU_UNIQUE or STT_GNU_IFUNC would need special casing.
   129     if ((ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE) && (ehdr->e_ident[EI_ABIVERSION] != 0))
   130         throw std::runtime_error("unsupported ELF ABI");
   132     if (ehdr->e_version != 1)
   133         throw std::runtime_error("unsupported ELF version");
   135     // Sanity checks
   136     if (ehdr->e_shnum == 0)
   137         throw std::runtime_error("sstripped ELF files aren't supported");
   139     if (ehdr->e_ehsize != Elf_Ehdr::size(e_ident[EI_CLASS]))
   140         throw std::runtime_error("unsupported ELF inconsistency: ehdr.e_ehsize != sizeof(ehdr)");
   142     if (ehdr->e_shentsize != Elf_Shdr::size(e_ident[EI_CLASS]))
   143         throw std::runtime_error("unsupported ELF inconsistency: ehdr.e_shentsize != sizeof(shdr)");
   145     if (ehdr->e_phnum == 0) {
   146         if (ehdr->e_phoff != 0)
   147             throw std::runtime_error("unsupported ELF inconsistency: e_phnum == 0 && e_phoff != 0");
   148         if (ehdr->e_phentsize != 0)
   149             throw std::runtime_error("unsupported ELF inconsistency: e_phnum == 0 && e_phentsize != 0");
   150     } else if (ehdr->e_phoff != ehdr->e_ehsize)
   151         throw std::runtime_error("unsupported ELF inconsistency: ehdr->e_phoff != ehdr->e_ehsize");
   152     else if (ehdr->e_phentsize != Elf_Phdr::size(e_ident[EI_CLASS]))
   153         throw std::runtime_error("unsupported ELF inconsistency: ehdr->e_phentsize != sizeof(phdr)");
   155     // Read section headers
   156     Elf_Shdr **shdr = new Elf_Shdr *[ehdr->e_shnum];
   157     file.seekg(ehdr->e_shoff);
   158     for (int i = 0; i < ehdr->e_shnum; i++)
   159         shdr[i] = new Elf_Shdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
   161     // Sanity check in section header for index 0
   162     if ((shdr[0]->sh_name != 0) || (shdr[0]->sh_type != SHT_NULL) ||
   163         (shdr[0]->sh_flags != 0) || (shdr[0]->sh_addr != 0) ||
   164         (shdr[0]->sh_offset != 0) || (shdr[0]->sh_size != 0) ||
   165         (shdr[0]->sh_link != SHN_UNDEF) || (shdr[0]->sh_info != 0) ||
   166         (shdr[0]->sh_addralign != 0) || (shdr[0]->sh_entsize != 0))
   167         throw std::runtime_error("Section header for index 0 contains unsupported values");
   169     if ((shdr[ehdr->e_shstrndx]->sh_link != 0) || (shdr[ehdr->e_shstrndx]->sh_info != 0))
   170         throw std::runtime_error("unsupported ELF content: string table with sh_link != 0 || sh_info != 0");
   172     // Store these temporarily
   173     tmp_shdr = shdr;
   174     tmp_file = &file;
   176     // Fill sections list
   177     sections = new ElfSection *[ehdr->e_shnum];
   178     for (int i = 0; i < ehdr->e_shnum; i++)
   179         sections[i] = nullptr;
   180     for (int i = 1; i < ehdr->e_shnum; i++) {
   181         if (sections[i] != nullptr)
   182             continue;
   183         getSection(i);
   184     }
   185     Elf_Shdr s;
   186     s.sh_name = 0;
   187     s.sh_type = SHT_NULL;
   188     s.sh_flags = 0;
   189     s.sh_addr = 0;
   190     s.sh_offset = ehdr->e_shoff;
   191     s.sh_entsize = Elf_Shdr::size(e_ident[EI_CLASS]);
   192     s.sh_size = s.sh_entsize * ehdr->e_shnum;
   193     s.sh_link = 0;
   194     s.sh_info = 0;
   195     s.sh_addralign = (e_ident[EI_CLASS] == ELFCLASS32) ? 4 : 8;
   196     shdr_section = new ElfSection(s, nullptr, nullptr);
   198     // Fake section for program headers
   199     s.sh_offset = ehdr->e_phoff;
   200     s.sh_addr = ehdr->e_phoff;
   201     s.sh_entsize = Elf_Phdr::size(e_ident[EI_CLASS]);
   202     s.sh_size = s.sh_entsize * ehdr->e_phnum;
   203     phdr_section = new ElfSection(s, nullptr, nullptr);
   205     phdr_section->insertAfter(ehdr, false);
   207     sections[1]->insertAfter(phdr_section, false);
   208     for (int i = 2; i < ehdr->e_shnum; i++) {
   209         // TODO: this should be done in a better way
   210         if ((shdr_section->getPrevious() == nullptr) && (shdr[i]->sh_offset > ehdr->e_shoff)) {
   211             shdr_section->insertAfter(sections[i - 1], false);
   212             sections[i]->insertAfter(shdr_section, false);
   213         } else
   214             sections[i]->insertAfter(sections[i - 1], false);
   215     }
   216     if (shdr_section->getPrevious() == nullptr)
   217         shdr_section->insertAfter(sections[ehdr->e_shnum - 1], false);
   219     tmp_file = nullptr;
   220     tmp_shdr = nullptr;
   221     for (int i = 0; i < ehdr->e_shnum; i++)
   222         delete shdr[i];
   223     delete[] shdr;
   225     eh_shstrndx = (ElfStrtab_Section *)sections[ehdr->e_shstrndx];
   227     // Skip reading program headers if there aren't any
   228     if (ehdr->e_phnum == 0)
   229         return;
   231     // Read program headers
   232     file.seekg(ehdr->e_phoff);
   233     for (int i = 0; i < ehdr->e_phnum; i++) {
   234         Elf_Phdr phdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
   235         if (phdr.p_type == PT_LOAD) {
   236             // Default alignment for PT_LOAD on x86-64 prevents elfhack from
   237             // doing anything useful. However, the system doesn't actually
   238             // require such a big alignment, so in order for elfhack to work
   239             // efficiently, reduce alignment when it's originally the default
   240             // one.
   241             if ((ehdr->e_machine == EM_X86_64) && (phdr.p_align == 0x200000))
   242               phdr.p_align = 0x1000;
   243         }
   244         ElfSegment *segment = new ElfSegment(&phdr);
   245         // Some segments aren't entirely filled (if at all) by sections
   246         // For those, we use fake sections
   247         if ((phdr.p_type == PT_LOAD) && (phdr.p_offset == 0)) {
   248             // Use a fake section for ehdr and phdr
   249             ehdr->getShdr().sh_addr = phdr.p_vaddr;
   250             phdr_section->getShdr().sh_addr += phdr.p_vaddr;
   251             segment->addSection(ehdr);
   252             segment->addSection(phdr_section);
   253         }
   254         if (phdr.p_type == PT_PHDR)
   255             segment->addSection(phdr_section);
   256         for (int j = 1; j < ehdr->e_shnum; j++)
   257             if (phdr.contains(sections[j]))
   258                 segment->addSection(sections[j]);
   259         // Make sure that our view of segments corresponds to the original
   260         // ELF file.
   261         assert(segment->getFileSize() == phdr.p_filesz);
   262         // gold makes TLS segments end on an aligned virtual address, even
   263         // when the underlying section ends before that, while bfd ld
   264         // doesn't. It's fine if we don't keep that alignment.
   265         unsigned int memsize = segment->getMemSize();
   266         if (phdr.p_type == PT_TLS && memsize != phdr.p_memsz) {
   267             unsigned int align = segment->getAlign();
   268             memsize = (memsize + align - 1) & ~(align - 1);
   269         }
   270         assert(memsize == phdr.p_memsz);
   271         segments.push_back(segment);
   272     }
   274     new (&eh_entry) ElfLocation(ehdr->e_entry, this);
   275 }
   277 Elf::~Elf()
   278 {
   279     for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
   280         delete *seg;
   281     delete[] sections;
   282     ElfSection *section = ehdr;
   283     while (section != nullptr) {
   284         ElfSection *next = section->getNext();
   285         delete section;
   286         section = next;
   287     }
   288 }
   290 // TODO: This shouldn't fail after inserting sections
   291 ElfSection *Elf::getSection(int index)
   292 {
   293     if ((index < -1) || (index >= ehdr->e_shnum))
   294         throw std::runtime_error("Section index out of bounds");
   295     if (index == -1)
   296         index = ehdr->e_shstrndx; // TODO: should be fixed to use the actual current number
   297     // Special case: the section at index 0 is void
   298     if (index == 0)
   299         return nullptr;
   300     // Infinite recursion guard
   301     if (sections[index] == (ElfSection *)this)
   302         return nullptr;
   303     if (sections[index] == nullptr) {
   304         sections[index] = (ElfSection *)this;
   305         switch (tmp_shdr[index]->sh_type) {
   306         case SHT_DYNAMIC:
   307             sections[index] = new ElfDynamic_Section(*tmp_shdr[index], tmp_file, this);
   308             break;
   309         case SHT_REL:
   310             sections[index] = new ElfRel_Section<Elf_Rel>(*tmp_shdr[index], tmp_file, this);
   311             break;
   312         case SHT_RELA:
   313             sections[index] = new ElfRel_Section<Elf_Rela>(*tmp_shdr[index], tmp_file, this);
   314             break;
   315         case SHT_DYNSYM:
   316         case SHT_SYMTAB:
   317             sections[index] = new ElfSymtab_Section(*tmp_shdr[index], tmp_file, this);
   318             break;
   319         case SHT_STRTAB:
   320             sections[index] = new ElfStrtab_Section(*tmp_shdr[index], tmp_file, this);
   321             break;
   322         default:
   323             sections[index] = new ElfSection(*tmp_shdr[index], tmp_file, this);
   324         }
   325     }
   326     return sections[index];
   327 }
   329 ElfSection *Elf::getSectionAt(unsigned int offset)
   330 {
   331     for (int i = 1; i < ehdr->e_shnum; i++) {
   332         ElfSection *section = getSection(i);
   333         if ((section != nullptr) && (section->getFlags() & SHF_ALLOC) && !(section->getFlags() & SHF_TLS) &&
   334             (offset >= section->getAddr()) && (offset < section->getAddr() + section->getSize()))
   335             return section;
   336     }
   337     return nullptr;
   338 }
   340 ElfSegment *Elf::getSegmentByType(unsigned int type, ElfSegment *last)
   341 {
   342     std::vector<ElfSegment *>::iterator seg;
   343     if (last) {
   344         seg = std::find(segments.begin(), segments.end(), last);
   345         ++seg;
   346     } else
   347         seg = segments.begin();
   348     for (; seg != segments.end(); seg++)
   349         if ((*seg)->getType() == type)
   350             return *seg;
   351     return nullptr;
   352 }
   354 void Elf::removeSegment(ElfSegment *segment)
   355 {
   356     if (!segment)
   357         return;
   358     std::vector<ElfSegment *>::iterator seg;
   359     seg = std::find(segments.begin(), segments.end(), segment);
   360     if (seg == segments.end())
   361         return;
   362     segment->clear();
   363     segments.erase(seg);
   364 }
   366 ElfDynamic_Section *Elf::getDynSection()
   367 {
   368     for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
   369         if (((*seg)->getType() == PT_DYNAMIC) && ((*seg)->getFirstSection() != nullptr) &&
   370             (*seg)->getFirstSection()->getType() == SHT_DYNAMIC)
   371             return (ElfDynamic_Section *)(*seg)->getFirstSection();
   373     return nullptr;
   374 }
   376 void Elf::normalize()
   377 {
   378     // fixup section headers sh_name; TODO: that should be done by sections
   379     // themselves
   380     for (ElfSection *section = ehdr; section != nullptr; section = section->getNext()) {
   381         if (section->getIndex() == 0)
   382             continue;
   383         else
   384             ehdr->e_shnum = section->getIndex() + 1;
   385         section->getShdr().sh_name = eh_shstrndx->getStrIndex(section->getName());
   386     }
   387     ehdr->markDirty();
   388     // Check segments consistency
   389     int i = 0;
   390     for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++, i++) {
   391         std::list<ElfSection *>::iterator it = (*seg)->begin();
   392         for (ElfSection *last = *(it++); it != (*seg)->end(); last = *(it++)) {
   393             if (((*it)->getType() != SHT_NOBITS) &&
   394                 ((*it)->getAddr() - last->getAddr()) != ((*it)->getOffset() - last->getOffset())) {
   395                     throw std::runtime_error("Segments inconsistency");
   396             }
   397         }
   398     }
   399     // fixup ehdr before writing
   400     if (ehdr->e_phnum != segments.size()) {
   401         ehdr->e_phnum = segments.size();
   402         phdr_section->getShdr().sh_size = segments.size() * Elf_Phdr::size(ehdr->e_ident[EI_CLASS]);
   403         phdr_section->getNext()->markDirty();
   404     }
   405     // fixup shdr before writing
   406     if (ehdr->e_shnum != shdr_section->getSize() / shdr_section->getEntSize())
   407         shdr_section->getShdr().sh_size = ehdr->e_shnum * Elf_Shdr::size(ehdr->e_ident[EI_CLASS]);
   408     ehdr->e_shoff = shdr_section->getOffset();
   409     ehdr->e_entry = eh_entry.getValue();
   410     ehdr->e_shstrndx = eh_shstrndx->getIndex();
   411 }
   413 void Elf::write(std::ofstream &file)
   414 {
   415     normalize();
   416     for (ElfSection *section = ehdr;
   417          section != nullptr; section = section->getNext()) {
   418         file.seekp(section->getOffset());
   419         if (section == phdr_section) {
   420             for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++) {
   421                 Elf_Phdr phdr;
   422                 phdr.p_type = (*seg)->getType();
   423                 phdr.p_flags = (*seg)->getFlags();
   424                 phdr.p_offset = (*seg)->getOffset();
   425                 phdr.p_vaddr = (*seg)->getAddr();
   426                 phdr.p_paddr = phdr.p_vaddr + (*seg)->getVPDiff();
   427                 phdr.p_filesz = (*seg)->getFileSize();
   428                 phdr.p_memsz = (*seg)->getMemSize();
   429                 phdr.p_align = (*seg)->getAlign();
   430                 phdr.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
   431             }
   432         } else if (section == shdr_section) {
   433             null_section.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
   434             for (ElfSection *sec = ehdr; sec!= nullptr; sec = sec->getNext()) {
   435                 if (sec->getType() != SHT_NULL)
   436                     sec->getShdr().serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
   437             }
   438         } else
   439            section->serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
   440     }
   441 }
   443 ElfSection::ElfSection(Elf_Shdr &s, std::ifstream *file, Elf *parent)
   444 : shdr(s),
   445   link(shdr.sh_link == SHN_UNDEF ? nullptr : parent->getSection(shdr.sh_link)),
   446   next(nullptr), previous(nullptr), index(-1)
   447 {
   448     if ((file == nullptr) || (shdr.sh_type == SHT_NULL) || (shdr.sh_type == SHT_NOBITS))
   449         data = nullptr;
   450     else {
   451         data = new char[shdr.sh_size];
   452         int pos = file->tellg();
   453         file->seekg(shdr.sh_offset);
   454         file->read(data, shdr.sh_size);
   455         file->seekg(pos);
   456     }
   457     if (shdr.sh_name == 0)
   458         name = nullptr;
   459     else {
   460         ElfStrtab_Section *strtab = (ElfStrtab_Section *) parent->getSection(-1);
   461         // Special case (see elfgeneric.cpp): if strtab is nullptr, the
   462         // section being created is the strtab.
   463         if (strtab == nullptr)
   464             name = &data[shdr.sh_name];
   465         else
   466             name = strtab->getStr(shdr.sh_name);
   467     }
   468     // Only SHT_REL/SHT_RELA sections use sh_info to store a section
   469     // number.
   470     if ((shdr.sh_type == SHT_REL) || (shdr.sh_type == SHT_RELA))
   471         info.section = shdr.sh_info ? parent->getSection(shdr.sh_info) : nullptr;
   472     else
   473         info.index = shdr.sh_info;
   474 }
   476 unsigned int ElfSection::getAddr()
   477 {
   478     if (shdr.sh_addr != (Elf32_Word)-1)
   479         return shdr.sh_addr;
   481     // It should be safe to adjust sh_addr for all allocated sections that
   482     // are neither SHT_NOBITS nor SHT_PROGBITS
   483     if ((previous != nullptr) && isRelocatable()) {
   484         unsigned int addr = previous->getAddr();
   485         if (previous->getType() != SHT_NOBITS)
   486             addr += previous->getSize();
   488         if (addr & (getAddrAlign() - 1))
   489             addr = (addr | (getAddrAlign() - 1)) + 1;
   491         return (shdr.sh_addr = addr);
   492     }
   493     return shdr.sh_addr;
   494 }
   496 unsigned int ElfSection::getOffset()
   497 {
   498     if (shdr.sh_offset != (Elf32_Word)-1)
   499         return shdr.sh_offset;
   501     if (previous == nullptr)
   502         return (shdr.sh_offset = 0);
   504     unsigned int offset = previous->getOffset();
   506     ElfSegment *ptload = getSegmentByType(PT_LOAD);
   507     ElfSegment *prev_ptload = previous->getSegmentByType(PT_LOAD);
   509     if (ptload && (ptload == prev_ptload)) {
   510         offset += getAddr() - previous->getAddr();
   511         return (shdr.sh_offset = offset);
   512     }
   514     if (previous->getType() != SHT_NOBITS)
   515         offset += previous->getSize();
   517     Elf32_Word align = 0x1000;
   518     for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
   519         align = std::max(align, (*seg)->getAlign());
   521     Elf32_Word mask = align - 1;
   522     // SHF_TLS is used for .tbss which is some kind of special case.
   523     if (((getType() != SHT_NOBITS) || (getFlags() & SHF_TLS)) && (getFlags() & SHF_ALLOC)) {
   524         if ((getAddr() & mask) < (offset & mask))
   525             offset = (offset | mask) + (getAddr() & mask) + 1;
   526         else
   527             offset = (offset & ~mask) + (getAddr() & mask);
   528     }
   529     if ((getType() != SHT_NOBITS) && (offset & (getAddrAlign() - 1)))
   530         offset = (offset | (getAddrAlign() - 1)) + 1;
   532     // Two subsequent sections can't be mapped in the same page in memory
   533     // if they aren't in the same 4K block on disk.
   534     if ((getType() != SHT_NOBITS) && getAddr()) {
   535         if (((offset >> 12) != (previous->getOffset() >> 12)) &&
   536             ((getAddr() >> 12) == (previous->getAddr() >> 12)))
   537             throw std::runtime_error("Moving section would require overlapping segments");
   538     }
   540     return (shdr.sh_offset = offset);
   541 }
   543 int ElfSection::getIndex()
   544 {
   545     if (index != -1)
   546         return index;
   547     if (getType() == SHT_NULL)
   548         return (index = 0);
   549     ElfSection *reference;
   550     for (reference = previous; (reference != nullptr) && (reference->getType() == SHT_NULL); reference = reference->getPrevious());
   551     if (reference == nullptr)
   552         return (index = 1);
   553     return (index = reference->getIndex() + 1);
   554 }
   556 Elf_Shdr &ElfSection::getShdr()
   557 {
   558     getOffset();
   559     if (shdr.sh_link == (Elf32_Word)-1)
   560         shdr.sh_link = getLink() ? getLink()->getIndex() : 0;
   561     if (shdr.sh_info == (Elf32_Word)-1)
   562         shdr.sh_info = ((getType() == SHT_REL) || (getType() == SHT_RELA)) ?
   563                        (getInfo().section ? getInfo().section->getIndex() : 0) :
   564                        getInfo().index;
   566     return shdr;
   567 }
   569 ElfSegment::ElfSegment(Elf_Phdr *phdr)
   570 : type(phdr->p_type), v_p_diff(phdr->p_paddr - phdr->p_vaddr),
   571   flags(phdr->p_flags), align(phdr->p_align), vaddr(phdr->p_vaddr),
   572   filesz(phdr->p_filesz), memsz(phdr->p_memsz) {}
   574 void ElfSegment::addSection(ElfSection *section)
   575 {
   576     // Make sure all sections in PT_GNU_RELRO won't be moved by elfhack
   577     assert(!((type == PT_GNU_RELRO) && (section->isRelocatable())));
   579     //TODO: Check overlapping sections
   580     std::list<ElfSection *>::iterator i;
   581     for (i = sections.begin(); i != sections.end(); ++i)
   582         if ((*i)->getAddr() > section->getAddr())
   583             break;
   584     sections.insert(i, section);
   585     section->addToSegment(this);
   586 }
   588 void ElfSegment::removeSection(ElfSection *section)
   589 {
   590     sections.remove(section);
   591     section->removeFromSegment(this);
   592 }
   594 unsigned int ElfSegment::getFileSize()
   595 {
   596     if (type == PT_GNU_RELRO || isElfHackFillerSegment())
   597         return filesz;
   599     if (sections.empty())
   600         return 0;
   601     // Search the last section that is not SHT_NOBITS
   602     std::list<ElfSection *>::reverse_iterator i;
   603     for (i = sections.rbegin(); (i != sections.rend()) && ((*i)->getType() == SHT_NOBITS); ++i);
   604     // All sections are SHT_NOBITS
   605     if (i == sections.rend())
   606         return 0;
   608     unsigned int end = (*i)->getAddr() + (*i)->getSize();
   610     return end - sections.front()->getAddr();
   611 }
   613 unsigned int ElfSegment::getMemSize()
   614 {
   615     if (type == PT_GNU_RELRO || isElfHackFillerSegment())
   616         return memsz;
   618     if (sections.empty())
   619         return 0;
   621     unsigned int end = sections.back()->getAddr() + sections.back()->getSize();
   623     return end - sections.front()->getAddr();
   624 }
   626 unsigned int ElfSegment::getOffset()
   627 {
   628     if ((type == PT_GNU_RELRO) && !sections.empty() &&
   629         (sections.front()->getAddr() != vaddr))
   630         throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
   632     // Neither bionic nor glibc linkers seem to like when the offset of that segment is 0
   633     if (isElfHackFillerSegment())
   634         return vaddr;
   636     return sections.empty() ? 0 : sections.front()->getOffset();
   637 }
   639 unsigned int ElfSegment::getAddr()
   640 {
   641     if ((type == PT_GNU_RELRO) && !sections.empty() &&
   642         (sections.front()->getAddr() != vaddr))
   643         throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
   645     if (isElfHackFillerSegment())
   646         return vaddr;
   648     return sections.empty() ? 0 : sections.front()->getAddr();
   649 }
   651 void ElfSegment::clear()
   652 {
   653     for (std::list<ElfSection *>::iterator i = sections.begin(); i != sections.end(); ++i)
   654         (*i)->removeFromSegment(this);
   655     sections.clear();
   656 }
   658 ElfValue *ElfDynamic_Section::getValueForType(unsigned int tag)
   659 {
   660     for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++)
   661         if (dyns[i].tag == tag)
   662             return dyns[i].value;
   664     return nullptr;
   665 }
   667 ElfSection *ElfDynamic_Section::getSectionForType(unsigned int tag)
   668 {
   669     ElfValue *value = getValueForType(tag);
   670     return value ? value->getSection() : nullptr;
   671 }
   673 bool ElfDynamic_Section::setValueForType(unsigned int tag, ElfValue *val)
   674 {
   675     unsigned int i;
   676     unsigned int shnum = shdr.sh_size / shdr.sh_entsize;
   677     for (i = 0; (i < shnum) && (dyns[i].tag != DT_NULL); i++)
   678         if (dyns[i].tag == tag) {
   679             delete dyns[i].value;
   680             dyns[i].value = val;
   681             return true;
   682         }
   683     // If we get here, this means we didn't match for the given tag
   684     // Most of the time, there are a few DT_NULL entries, that we can
   685     // use to add our value, but if we are on the last entry, we can't.
   686     if (i >= shnum - 1)
   687         return false;
   689     dyns[i].tag = tag;
   690     dyns[i].value = val;
   691     return true;
   692 }
   694 ElfDynamic_Section::ElfDynamic_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
   695 : ElfSection(s, file, parent)
   696 {
   697     int pos = file->tellg();
   698     dyns.resize(s.sh_size / s.sh_entsize);
   699     file->seekg(shdr.sh_offset);
   700     // Here we assume tags refer to only one section (e.g. DT_RELSZ accounts
   701     // for .rel.dyn size)
   702     for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) {
   703         Elf_Dyn dyn(*file, parent->getClass(), parent->getData());
   704         dyns[i].tag = dyn.d_tag;
   705         switch (dyn.d_tag) {
   706         case DT_NULL:
   707         case DT_SYMBOLIC:
   708         case DT_TEXTREL:
   709         case DT_BIND_NOW:
   710             dyns[i].value = new ElfValue();
   711             break;
   712         case DT_NEEDED:
   713         case DT_SONAME:
   714         case DT_RPATH:
   715         case DT_PLTREL:
   716         case DT_RUNPATH:
   717         case DT_FLAGS:
   718         case DT_RELACOUNT:
   719         case DT_RELCOUNT:
   720         case DT_VERDEFNUM:
   721         case DT_VERNEEDNUM:
   722             dyns[i].value = new ElfPlainValue(dyn.d_un.d_val);
   723             break;
   724         case DT_PLTGOT:
   725         case DT_HASH:
   726         case DT_STRTAB:
   727         case DT_SYMTAB:
   728         case DT_RELA:
   729         case DT_INIT:
   730         case DT_FINI:
   731         case DT_REL:
   732         case DT_JMPREL:
   733         case DT_INIT_ARRAY:
   734         case DT_FINI_ARRAY:
   735         case DT_GNU_HASH:
   736         case DT_VERSYM:
   737         case DT_VERNEED:
   738         case DT_VERDEF:
   739             dyns[i].value = new ElfLocation(dyn.d_un.d_ptr, parent);
   740             break;
   741         default:
   742             dyns[i].value = nullptr;
   743         }
   744     }
   745     // Another loop to get the section sizes
   746     for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++)
   747         switch (dyns[i].tag) {
   748         case DT_PLTRELSZ:
   749             dyns[i].value = new ElfSize(getSectionForType(DT_JMPREL));
   750             break;
   751         case DT_RELASZ:
   752             dyns[i].value = new ElfSize(getSectionForType(DT_RELA));
   753             break;
   754         case DT_STRSZ:
   755             dyns[i].value = new ElfSize(getSectionForType(DT_STRTAB));
   756             break;
   757         case DT_RELSZ:
   758             dyns[i].value = new ElfSize(getSectionForType(DT_REL));
   759             break;
   760         case DT_INIT_ARRAYSZ:
   761             dyns[i].value = new ElfSize(getSectionForType(DT_INIT_ARRAY));
   762             break;
   763         case DT_FINI_ARRAYSZ:
   764             dyns[i].value = new ElfSize(getSectionForType(DT_FINI_ARRAY));
   765             break;
   766         case DT_RELAENT:
   767             dyns[i].value = new ElfEntSize(getSectionForType(DT_RELA));
   768             break;
   769         case DT_SYMENT:
   770             dyns[i].value = new ElfEntSize(getSectionForType(DT_SYMTAB));
   771             break;
   772         case DT_RELENT:
   773             dyns[i].value = new ElfEntSize(getSectionForType(DT_REL));
   774             break;
   775         }
   777     file->seekg(pos);
   778 }
   780 ElfDynamic_Section::~ElfDynamic_Section()
   781 {
   782     for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++)
   783         delete dyns[i].value;
   784 }
   786 void ElfDynamic_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
   787 {
   788     for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
   789         Elf_Dyn dyn;
   790         dyn.d_tag = dyns[i].tag;
   791         dyn.d_un.d_val = (dyns[i].value != nullptr) ? dyns[i].value->getValue() : 0;
   792         dyn.serialize(file, ei_class, ei_data);
   793     }
   794 }
   796 ElfSymtab_Section::ElfSymtab_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
   797 : ElfSection(s, file, parent)
   798 {
   799     int pos = file->tellg();
   800     syms.resize(s.sh_size / s.sh_entsize);
   801     ElfStrtab_Section *strtab = (ElfStrtab_Section *)getLink();
   802     file->seekg(shdr.sh_offset);
   803     for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
   804         Elf_Sym sym(*file, parent->getClass(), parent->getData());
   805         syms[i].name = strtab->getStr(sym.st_name);
   806         syms[i].info = sym.st_info;
   807         syms[i].other = sym.st_other;
   808         ElfSection *section = (sym.st_shndx == SHN_ABS) ? nullptr : parent->getSection(sym.st_shndx);
   809         new (&syms[i].value) ElfLocation(section, sym.st_value, ElfLocation::ABSOLUTE);
   810         syms[i].size = sym.st_size;
   811         syms[i].defined = (sym.st_shndx != SHN_UNDEF);
   812     }
   813     file->seekg(pos);
   814 }
   816 void
   817 ElfSymtab_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
   818 {
   819     ElfStrtab_Section *strtab = (ElfStrtab_Section *)getLink();
   820     for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
   821         Elf_Sym sym;
   822         sym.st_name = strtab->getStrIndex(syms[i].name);
   823         sym.st_info = syms[i].info;
   824         sym.st_other = syms[i].other;
   825         sym.st_value = syms[i].value.getValue();
   826         ElfSection *section = syms[i].value.getSection();
   827         if (syms[i].defined)
   828             sym.st_shndx = section ? section->getIndex() : SHN_ABS;
   829         else
   830             sym.st_shndx = SHN_UNDEF;
   831         sym.st_size = syms[i].size;
   832         sym.serialize(file, ei_class, ei_data);
   833     }
   834 }
   836 Elf_SymValue *
   837 ElfSymtab_Section::lookup(const char *name, unsigned int type_filter)
   838 {
   839     for (std::vector<Elf_SymValue>::iterator sym = syms.begin();
   840          sym != syms.end(); sym++) {
   841         if ((type_filter & (1 << ELF32_ST_TYPE(sym->info))) &&
   842             (strcmp(sym->name, name) == 0)) {
   843             return &*sym;
   844         }
   845     }
   846     return nullptr;
   847 }
   849 const char *
   850 ElfStrtab_Section::getStr(unsigned int index)
   851 {
   852     for (std::vector<table_storage>::iterator t = table.begin();
   853          t != table.end(); t++) {
   854         if (index < t->used)
   855             return t->buf + index;
   856         index -= t->used;
   857     }
   858     assert(1 == 0);
   859     return nullptr;
   860 }
   862 const char *
   863 ElfStrtab_Section::getStr(const char *string)
   864 {
   865     if (string == nullptr)
   866         return nullptr;
   868     // If the given string is within the section, return it
   869     for (std::vector<table_storage>::iterator t = table.begin();
   870          t != table.end(); t++)
   871         if ((string >= t->buf) && (string < t->buf + t->used))
   872             return string;
   874     // TODO: should scan in the section to find an existing string
   876     // If not, we need to allocate the string in the section
   877     size_t len = strlen(string) + 1;
   879     if (table.back().size - table.back().used < len)
   880         table.resize(table.size() + 1);
   882     char *alloc_str = table.back().buf + table.back().used;
   883     memcpy(alloc_str, string, len);
   884     table.back().used += len;
   886     shdr.sh_size += len;
   887     markDirty();
   889     return alloc_str;
   890 }
   892 unsigned int
   893 ElfStrtab_Section::getStrIndex(const char *string)
   894 {
   895     if (string == nullptr)
   896         return 0;
   898     unsigned int index = 0;
   899     string = getStr(string);
   900     for (std::vector<table_storage>::iterator t = table.begin();
   901          t != table.end(); t++) {
   902         if ((string >= t->buf) && (string < t->buf + t->used))
   903             return index + (string - t->buf);
   904         index += t->used;
   905     }
   907     assert(1 == 0);
   908     return 0;
   909 }
   911 void
   912 ElfStrtab_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
   913 {
   914     file.seekp(getOffset());
   915     for (std::vector<table_storage>::iterator t = table.begin();
   916          t != table.end(); t++)
   917         file.write(t->buf, t->used);
   918 }

mercurial