Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always use rewriteSectionsLibrary #483

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 1 addition & 211 deletions src/patchelf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -485,89 +485,6 @@ static uint64_t roundUp(uint64_t n, uint64_t m)
}


template<ElfFileParams>
void ElfFile<ElfFileParamNames>::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<ElfFileParams>
std::string ElfFile<ElfFileParamNames>::getSectionName(const Elf_Shdr & shdr) const
{
Expand Down Expand Up @@ -921,133 +838,6 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()

static bool noSort = false;

template<ElfFileParams>
void ElfFile<ElfFileParamNames>::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<ElfFileParams>
void ElfFile<ElfFileParamNames>::normalizeNoteSegments()
{
Expand Down Expand Up @@ -1131,7 +921,7 @@ void ElfFile<ElfFileParamNames>::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");
}

Expand Down
4 changes: 0 additions & 4 deletions src/patchelf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -129,8 +127,6 @@ class ElfFile

void rewriteSectionsLibrary();

void rewriteSectionsExecutable();

void normalizeNoteSegments();

public:
Expand Down