diff --git a/src/patchelf.cc b/src/patchelf.cc index 1a90edb1..458ca367 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -485,89 +485,6 @@ static uint64_t roundUp(uint64_t n, uint64_t m) } -template -void ElfFile::shiftFile(unsigned int extraPages, size_t startOffset, size_t extraBytes) -{ - assert(startOffset >= sizeof(Elf_Ehdr)); - - unsigned int oldSize = fileContents->size(); - assert(oldSize > startOffset); - - /* Move the entire contents of the file after 'startOffset' by 'extraPages' pages further. */ - unsigned int shift = extraPages * getPageSize(); - fileContents->resize(oldSize + shift, 0); - memmove(fileContents->data() + startOffset + shift, fileContents->data() + startOffset, oldSize - startOffset); - memset(fileContents->data() + startOffset, 0, shift); - - /* Adjust the ELF header. */ - wri(hdr()->e_phoff, sizeof(Elf_Ehdr)); - if (rdi(hdr()->e_shoff) >= startOffset) - wri(hdr()->e_shoff, rdi(hdr()->e_shoff) + shift); - - /* Update the offsets in the section headers. */ - for (int i = 1; i < rdi(hdr()->e_shnum); ++i) { - size_t sh_offset = rdi(shdrs.at(i).sh_offset); - if (sh_offset >= startOffset) - wri(shdrs.at(i).sh_offset, sh_offset + shift); - } - - int splitIndex = -1; - size_t splitShift = 0; - - /* Update the offsets in the program headers. */ - for (int i = 0; i < rdi(hdr()->e_phnum); ++i) { - Elf_Off p_start = rdi(phdrs.at(i).p_offset); - - if (p_start <= startOffset && p_start + rdi(phdrs.at(i).p_filesz) > startOffset && rdi(phdrs.at(i).p_type) == PT_LOAD) { - assert(splitIndex == -1); - - splitIndex = i; - splitShift = startOffset - p_start; - - /* This is the load segment we're currently extending within, so we split it. */ - wri(phdrs.at(i).p_offset, startOffset); - wri(phdrs.at(i).p_memsz, rdi(phdrs.at(i).p_memsz) - splitShift); - wri(phdrs.at(i).p_filesz, rdi(phdrs.at(i).p_filesz) - splitShift); - wri(phdrs.at(i).p_paddr, rdi(phdrs.at(i).p_paddr) + splitShift); - wri(phdrs.at(i).p_vaddr, rdi(phdrs.at(i).p_vaddr) + splitShift); - - p_start = startOffset; - } - - if (p_start >= startOffset) { - wri(phdrs.at(i).p_offset, p_start + shift); - if (rdi(phdrs.at(i).p_align) != 0 && - (rdi(phdrs.at(i).p_vaddr) - rdi(phdrs.at(i).p_offset)) % rdi(phdrs.at(i).p_align) != 0) { - debug("changing alignment of program header %d from %d to %d\n", i, - rdi(phdrs.at(i).p_align), getPageSize()); - wri(phdrs.at(i).p_align, getPageSize()); - } - } else { - /* If we're not physically shifting, shift back virtual memory. */ - if (rdi(phdrs.at(i).p_paddr) >= shift) - wri(phdrs.at(i).p_paddr, rdi(phdrs.at(i).p_paddr) - shift); - if (rdi(phdrs.at(i).p_vaddr) >= shift) - wri(phdrs.at(i).p_vaddr, rdi(phdrs.at(i).p_vaddr) - shift); - } - } - - assert(splitIndex != -1); - - /* Add a segment that maps the new program/section headers and - PT_INTERP segment into memory. Otherwise glibc will choke. */ - phdrs.resize(rdi(hdr()->e_phnum) + 1); - wri(hdr()->e_phnum, rdi(hdr()->e_phnum) + 1); - Elf_Phdr & phdr = phdrs.at(rdi(hdr()->e_phnum) - 1); - wri(phdr.p_type, PT_LOAD); - wri(phdr.p_offset, phdrs.at(splitIndex).p_offset - splitShift - shift); - wri(phdr.p_paddr, phdrs.at(splitIndex).p_paddr - splitShift - shift); - wri(phdr.p_vaddr, phdrs.at(splitIndex).p_vaddr - splitShift - shift); - wri(phdr.p_filesz, wri(phdr.p_memsz, splitShift + extraBytes)); - wri(phdr.p_flags, PF_R | PF_W); - wri(phdr.p_align, getPageSize()); -} - - template std::string ElfFile::getSectionName(const Elf_Shdr & shdr) const { @@ -921,133 +838,6 @@ void ElfFile::rewriteSectionsLibrary() static bool noSort = false; -template -void ElfFile::rewriteSectionsExecutable() -{ - if (!noSort) { - /* Sort the sections by offset, otherwise we won't correctly find - all the sections before the last replaced section. */ - sortShdrs(); - } - - /* What is the index of the last replaced section? */ - unsigned int lastReplaced = 0; - for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i) { - std::string sectionName = getSectionName(shdrs.at(i)); - if (replacedSections.count(sectionName)) { - debug("using replaced section '%s'\n", sectionName.c_str()); - lastReplaced = i; - } - } - - assert(lastReplaced != 0); - - debug("last replaced is %d\n", lastReplaced); - - /* Try to replace all sections before that, as far as possible. - Stop when we reach an irreplacable section (such as one of type - SHT_PROGBITS). These cannot be moved in virtual address space - since that would invalidate absolute references to them. */ - assert(lastReplaced + 1 < shdrs.size()); /* !!! I'm lazy. */ - size_t startOffset = rdi(shdrs.at(lastReplaced + 1).sh_offset); - Elf_Addr startAddr = rdi(shdrs.at(lastReplaced + 1).sh_addr); - std::string prevSection; - for (unsigned int i = 1; i <= lastReplaced; ++i) { - Elf_Shdr & shdr(shdrs.at(i)); - std::string sectionName = getSectionName(shdr); - debug("looking at section '%s'\n", sectionName.c_str()); - /* !!! Why do we stop after a .dynstr section? I can't - remember! */ - if ((rdi(shdr.sh_type) == SHT_PROGBITS && sectionName != ".interp") - || prevSection == ".dynstr") - { - startOffset = rdi(shdr.sh_offset); - startAddr = rdi(shdr.sh_addr); - lastReplaced = i - 1; - break; - } - if (!replacedSections.count(sectionName)) { - debug("replacing section '%s' which is in the way\n", sectionName.c_str()); - replaceSection(sectionName, rdi(shdr.sh_size)); - } - prevSection = std::move(sectionName); - } - - debug("first reserved offset/addr is 0x%x/0x%llx\n", - startOffset, (unsigned long long) startAddr); - - assert(startAddr % getPageSize() == startOffset % getPageSize()); - Elf_Addr firstPage = startAddr - startOffset; - debug("first page is 0x%llx\n", (unsigned long long) firstPage); - - if (rdi(hdr()->e_shoff) < startOffset) { - /* The section headers occur too early in the file and would be - overwritten by the replaced sections. Move them to the end of the file - before proceeding. */ - off_t shoffNew = fileContents->size(); - off_t shSize = rdi(hdr()->e_shoff) + rdi(hdr()->e_shnum) * rdi(hdr()->e_shentsize); - fileContents->resize(fileContents->size() + shSize, 0); - wri(hdr()->e_shoff, shoffNew); - - /* Rewrite the section header table. For neatness, keep the - sections sorted. */ - assert(rdi(hdr()->e_shnum) == shdrs.size()); - sortShdrs(); - for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i) - * ((Elf_Shdr *) (fileContents->data() + rdi(hdr()->e_shoff)) + i) = shdrs.at(i); - } - - - normalizeNoteSegments(); - - - /* Compute the total space needed for the replaced sections, the - ELF header, and the program headers. */ - size_t neededSpace = sizeof(Elf_Ehdr) + phdrs.size() * sizeof(Elf_Phdr); - for (auto & i : replacedSections) - neededSpace += roundUp(i.second.size(), sectionAlignment); - - debug("needed space is %d\n", neededSpace); - - /* If we need more space at the start of the file, then grow the - file by the minimum number of pages and adjust internal - offsets. */ - if (neededSpace > startOffset) { - /* We also need an additional program header, so adjust for that. */ - neededSpace += sizeof(Elf_Phdr); - debug("needed space is %d\n", neededSpace); - - /* Calculate how many bytes are needed out of the additional pages. */ - size_t extraSpace = neededSpace - startOffset; - // Always give one extra page to avoid colliding with segments that start at - // unaligned addresses and will be rounded down when loaded - unsigned int neededPages = 1 + roundUp(extraSpace, getPageSize()) / getPageSize(); - debug("needed pages is %d\n", neededPages); - if (neededPages * getPageSize() > firstPage) - error("virtual address space underrun!"); - - shiftFile(neededPages, startOffset, extraSpace); - - firstPage -= neededPages * getPageSize(); - startOffset += neededPages * getPageSize(); - } - - - /* Clear out the free space. */ - Elf_Off curOff = sizeof(Elf_Ehdr) + phdrs.size() * sizeof(Elf_Phdr); - debug("clearing first %d bytes\n", startOffset - curOff); - memset(fileContents->data() + curOff, 0, startOffset - curOff); - - - /* Write out the replaced sections. */ - writeReplacedSections(curOff, firstPage, 0); - assert(curOff == neededSpace); - - - rewriteHeaders(firstPage + rdi(hdr()->e_phoff)); -} - - template void ElfFile::normalizeNoteSegments() { @@ -1131,7 +921,7 @@ void ElfFile::rewriteSections(bool force) rewriteSectionsLibrary(); } else if (rdi(hdr()->e_type) == ET_EXEC) { debug("this is an executable\n"); - rewriteSectionsExecutable(); + rewriteSectionsLibrary(); } else error("unknown ELF type"); } diff --git a/src/patchelf.h b/src/patchelf.h index 9fab18c0..53cc000e 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -103,8 +103,6 @@ class ElfFile void sortShdrs(); - void shiftFile(unsigned int extraPages, size_t sizeOffset, size_t extraBytes); - [[nodiscard]] std::string getSectionName(const Elf_Shdr & shdr) const; const Elf_Shdr & findSectionHeader(const SectionName & sectionName) const; @@ -129,8 +127,6 @@ class ElfFile void rewriteSectionsLibrary(); - void rewriteSectionsExecutable(); - void normalizeNoteSegments(); public: