Merge pull request #256 from andrewla/master

Remove limits on output file size.
This commit is contained in:
Jörg Thalheim
2021-09-13 16:59:16 +01:00
committed by GitHub
4 changed files with 116 additions and 100 deletions

1
.gitignore vendored
View File

@@ -31,3 +31,4 @@ Makefile
/tests/main-scoped /tests/main-scoped
/tests/libbig-dynstr.debug /tests/libbig-dynstr.debug
/tests/contiguous-note-sections /tests/contiguous-note-sections
/tests/simple-pie

View File

@@ -94,9 +94,6 @@ public:
private: private:
unsigned char * contents;
Elf_Ehdr * hdr;
std::vector<Elf_Phdr> phdrs; std::vector<Elf_Phdr> phdrs;
std::vector<Elf_Shdr> shdrs; std::vector<Elf_Shdr> shdrs;
@@ -233,6 +230,14 @@ private:
t = rdi((I) i); t = rdi((I) i);
return i; return i;
} }
Elf_Ehdr *hdr() {
return (Elf_Ehdr *)fileContents->data();
}
const Elf_Ehdr *hdr() const {
return (const Elf_Ehdr *)fileContents->data();
}
}; };
@@ -305,13 +310,6 @@ __attribute__((noreturn)) static void error(const std::string & msg)
throw std::runtime_error(msg); throw std::runtime_error(msg);
} }
static void growFile(const FileContents & contents, size_t newSize)
{
if (newSize > contents->capacity()) error("maximum file size exceeded");
if (newSize <= contents->size()) return;
contents->resize(newSize, 0);
}
static FileContents readFile(const std::string & fileName, static FileContents readFile(const std::string & fileName,
size_t cutOff = std::numeric_limits<size_t>::max()) size_t cutOff = std::numeric_limits<size_t>::max())
{ {
@@ -324,9 +322,7 @@ static FileContents readFile(const std::string & fileName,
size_t size = std::min(cutOff, static_cast<size_t>(st.st_size)); size_t size = std::min(cutOff, static_cast<size_t>(st.st_size));
FileContents contents = std::make_shared<std::vector<unsigned char>>(); FileContents contents = std::make_shared<std::vector<unsigned char>>(size);
contents->reserve(size + 32 * 1024 * 1024);
contents->resize(size, 0);
int fd = open(fileName.c_str(), O_RDONLY); int fd = open(fileName.c_str(), O_RDONLY);
if (fd == -1) throw SysError(fmt("opening '", fileName, "'")); if (fd == -1) throw SysError(fmt("opening '", fileName, "'"));
@@ -387,44 +383,42 @@ static void checkPointer(const FileContents & contents, void * p, unsigned int s
template<ElfFileParams> template<ElfFileParams>
ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents) ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
: fileContents(fContents) : fileContents(fContents)
, contents(fileContents->data())
{ {
/* Check the ELF header for basic validity. */ /* Check the ELF header for basic validity. */
if (fileContents->size() < (off_t) sizeof(Elf_Ehdr)) error("missing ELF header"); if (fileContents->size() < (off_t) sizeof(Elf_Ehdr)) error("missing ELF header");
hdr = (Elf_Ehdr *) fileContents->data();
if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0) if (memcmp(hdr()->e_ident, ELFMAG, SELFMAG) != 0)
error("not an ELF executable"); error("not an ELF executable");
littleEndian = hdr->e_ident[EI_DATA] == ELFDATA2LSB; littleEndian = hdr()->e_ident[EI_DATA] == ELFDATA2LSB;
if (rdi(hdr->e_type) != ET_EXEC && rdi(hdr->e_type) != ET_DYN) if (rdi(hdr()->e_type) != ET_EXEC && rdi(hdr()->e_type) != ET_DYN)
error("wrong ELF type"); error("wrong ELF type");
if (rdi(hdr->e_phoff) + size_t(rdi(hdr->e_phnum) * rdi(hdr->e_phentsize)) > fileContents->size()) if (rdi(hdr()->e_phoff) + rdi(hdr()->e_phnum) * rdi(hdr()->e_phentsize) > fileContents->size())
error("program header table out of bounds"); error("program header table out of bounds");
if (rdi(hdr->e_shnum) == 0) if (rdi(hdr()->e_shnum) == 0)
error("no section headers. The input file is probably a statically linked, self-decompressing binary"); error("no section headers. The input file is probably a statically linked, self-decompressing binary");
if (rdi(hdr->e_shoff) + size_t(rdi(hdr->e_shnum) * rdi(hdr->e_shentsize)) > fileContents->size()) if (rdi(hdr()->e_shoff) + rdi(hdr()->e_shnum) * rdi(hdr()->e_shentsize) > fileContents->size())
error("section header table out of bounds"); error("section header table out of bounds");
if (rdi(hdr->e_phentsize) != sizeof(Elf_Phdr)) if (rdi(hdr()->e_phentsize) != sizeof(Elf_Phdr))
error("program headers have wrong size"); error("program headers have wrong size");
/* Copy the program and section headers. */ /* Copy the program and section headers. */
for (int i = 0; i < rdi(hdr->e_phnum); ++i) { for (int i = 0; i < rdi(hdr()->e_phnum); ++i) {
Elf_Phdr *phdr = (Elf_Phdr *) (contents + rdi(hdr->e_phoff)) + i; Elf_Phdr *phdr = (Elf_Phdr *) (fileContents->data() + rdi(hdr()->e_phoff)) + i;
checkPointer(fileContents, phdr, sizeof(*phdr)); checkPointer(fileContents, phdr, sizeof(*phdr));
phdrs.push_back(*phdr); phdrs.push_back(*phdr);
if (rdi(phdrs[i].p_type) == PT_INTERP) isExecutable = true; if (rdi(phdrs[i].p_type) == PT_INTERP) isExecutable = true;
} }
for (int i = 0; i < rdi(hdr->e_shnum); ++i) { for (int i = 0; i < rdi(hdr()->e_shnum); ++i) {
Elf_Shdr *shdr = (Elf_Shdr *) (contents + rdi(hdr->e_shoff)) + i; Elf_Shdr *shdr = (Elf_Shdr *) (fileContents->data() + rdi(hdr()->e_shoff)) + i;
checkPointer(fileContents, shdr, sizeof(*shdr)); checkPointer(fileContents, shdr, sizeof(*shdr));
shdrs.push_back(*shdr); shdrs.push_back(*shdr);
@@ -433,12 +427,12 @@ ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
/* Get the section header string table section (".shstrtab"). Its /* Get the section header string table section (".shstrtab"). Its
index in the section header table is given by e_shstrndx field index in the section header table is given by e_shstrndx field
of the ELF header. */ of the ELF header. */
unsigned int shstrtabIndex = rdi(hdr->e_shstrndx); unsigned int shstrtabIndex = rdi(hdr()->e_shstrndx);
if (shstrtabIndex >= shdrs.size()) if (shstrtabIndex >= shdrs.size())
error("string table index out of bounds"); error("string table index out of bounds");
unsigned int shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size); unsigned int shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size);
char * shstrtab = (char * ) contents + rdi(shdrs[shstrtabIndex].sh_offset); char * shstrtab = (char * ) fileContents->data() + rdi(shdrs[shstrtabIndex].sh_offset);
checkPointer(fileContents, shstrtab, shstrtabSize); checkPointer(fileContents, shstrtab, shstrtabSize);
if (shstrtabSize == 0) if (shstrtabSize == 0)
@@ -464,7 +458,7 @@ unsigned int ElfFile<ElfFileParamNames>::getPageSize() const
// Architectures (and ABIs) can have different minimum section alignment // Architectures (and ABIs) can have different minimum section alignment
// requirements. There is no authoritative list of these values. The // requirements. There is no authoritative list of these values. The
// current list is extracted from GNU gold's source code (abi_pagesize). // current list is extracted from GNU gold's source code (abi_pagesize).
switch (rdi(hdr->e_machine)) { switch (rdi(hdr()->e_machine)) {
case EM_SPARC: case EM_SPARC:
case EM_MIPS: case EM_MIPS:
case EM_PPC: case EM_PPC:
@@ -494,19 +488,19 @@ void ElfFile<ElfFileParamNames>::sortShdrs()
/* Translate sh_link mappings to section names, since sorting the /* Translate sh_link mappings to section names, since sorting the
sections will invalidate the sh_link fields. */ sections will invalidate the sh_link fields. */
std::map<SectionName, SectionName> linkage; std::map<SectionName, SectionName> linkage;
for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i)
if (rdi(shdrs[i].sh_link) != 0) if (rdi(shdrs[i].sh_link) != 0)
linkage[getSectionName(shdrs[i])] = getSectionName(shdrs[rdi(shdrs[i].sh_link)]); linkage[getSectionName(shdrs[i])] = getSectionName(shdrs[rdi(shdrs[i].sh_link)]);
/* Idem for sh_info on certain sections. */ /* Idem for sh_info on certain sections. */
std::map<SectionName, SectionName> info; std::map<SectionName, SectionName> info;
for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i)
if (rdi(shdrs[i].sh_info) != 0 && if (rdi(shdrs[i].sh_info) != 0 &&
(rdi(shdrs[i].sh_type) == SHT_REL || rdi(shdrs[i].sh_type) == SHT_RELA)) (rdi(shdrs[i].sh_type) == SHT_REL || rdi(shdrs[i].sh_type) == SHT_RELA))
info[getSectionName(shdrs[i])] = getSectionName(shdrs[rdi(shdrs[i].sh_info)]); info[getSectionName(shdrs[i])] = getSectionName(shdrs[rdi(shdrs[i].sh_info)]);
/* Idem for the index of the .shstrtab section in the ELF header. */ /* Idem for the index of the .shstrtab section in the ELF header. */
Elf_Shdr shstrtab = shdrs[rdi(hdr->e_shstrndx)]; Elf_Shdr shstrtab = shdrs[rdi(hdr()->e_shstrndx)];
/* Sort the sections by offset. */ /* Sort the sections by offset. */
CompShdr comp; CompShdr comp;
@@ -514,13 +508,13 @@ void ElfFile<ElfFileParamNames>::sortShdrs()
stable_sort(shdrs.begin() + 1, shdrs.end(), comp); stable_sort(shdrs.begin() + 1, shdrs.end(), comp);
/* Restore the sh_link mappings. */ /* Restore the sh_link mappings. */
for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i)
if (rdi(shdrs[i].sh_link) != 0) if (rdi(shdrs[i].sh_link) != 0)
wri(shdrs[i].sh_link, wri(shdrs[i].sh_link,
findSection3(linkage[getSectionName(shdrs[i])])); findSection3(linkage[getSectionName(shdrs[i])]));
/* And the st_info mappings. */ /* And the st_info mappings. */
for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i)
if (rdi(shdrs[i].sh_info) != 0 && if (rdi(shdrs[i].sh_info) != 0 &&
(rdi(shdrs[i].sh_type) == SHT_REL || rdi(shdrs[i].sh_type) == SHT_RELA)) (rdi(shdrs[i].sh_type) == SHT_REL || rdi(shdrs[i].sh_type) == SHT_RELA))
wri(shdrs[i].sh_info, wri(shdrs[i].sh_info,
@@ -528,10 +522,10 @@ void ElfFile<ElfFileParamNames>::sortShdrs()
/* And the .shstrtab index. Note: the match here is done by checking the offset as searching /* And the .shstrtab index. Note: the match here is done by checking the offset as searching
* by name can yield incorrect results in case there are multiple sections with the same * by name can yield incorrect results in case there are multiple sections with the same
* name as the one initially pointed by hdr->e_shstrndx */ * name as the one initially pointed by hdr()->e_shstrndx */
for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) { for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i) {
if (shdrs[i].sh_offset == shstrtab.sh_offset) { if (shdrs[i].sh_offset == shstrtab.sh_offset) {
wri(hdr->e_shstrndx, i); wri(hdr()->e_shstrndx, i);
} }
} }
} }
@@ -584,20 +578,20 @@ void ElfFile<ElfFileParamNames>::shiftFile(unsigned int extraPages, Elf_Addr sta
further. */ further. */
unsigned int oldSize = fileContents->size(); unsigned int oldSize = fileContents->size();
unsigned int shift = extraPages * getPageSize(); unsigned int shift = extraPages * getPageSize();
growFile(fileContents, fileContents->size() + extraPages * getPageSize()); fileContents->resize(oldSize + shift, 0);
memmove(contents + extraPages * getPageSize(), contents, oldSize); memmove(fileContents->data() + shift, fileContents->data(), oldSize);
memset(contents + sizeof(Elf_Ehdr), 0, shift - sizeof(Elf_Ehdr)); memset(fileContents->data() + sizeof(Elf_Ehdr), 0, shift - sizeof(Elf_Ehdr));
/* Adjust the ELF header. */ /* Adjust the ELF header. */
wri(hdr->e_phoff, sizeof(Elf_Ehdr)); wri(hdr()->e_phoff, sizeof(Elf_Ehdr));
wri(hdr->e_shoff, rdi(hdr->e_shoff) + shift); wri(hdr()->e_shoff, rdi(hdr()->e_shoff) + shift);
/* Update the offsets in the section headers. */ /* Update the offsets in the section headers. */
for (int i = 1; i < rdi(hdr->e_shnum); ++i) for (int i = 1; i < rdi(hdr()->e_shnum); ++i)
wri(shdrs[i].sh_offset, rdi(shdrs[i].sh_offset) + shift); wri(shdrs[i].sh_offset, rdi(shdrs[i].sh_offset) + shift);
/* Update the offsets in the program headers. */ /* Update the offsets in the program headers. */
for (int i = 0; i < rdi(hdr->e_phnum); ++i) { for (int i = 0; i < rdi(hdr()->e_phnum); ++i) {
wri(phdrs[i].p_offset, rdi(phdrs[i].p_offset) + shift); wri(phdrs[i].p_offset, rdi(phdrs[i].p_offset) + shift);
if (rdi(phdrs[i].p_align) != 0 && if (rdi(phdrs[i].p_align) != 0 &&
(rdi(phdrs[i].p_vaddr) - rdi(phdrs[i].p_offset)) % rdi(phdrs[i].p_align) != 0) { (rdi(phdrs[i].p_vaddr) - rdi(phdrs[i].p_offset)) % rdi(phdrs[i].p_align) != 0) {
@@ -609,9 +603,9 @@ void ElfFile<ElfFileParamNames>::shiftFile(unsigned int extraPages, Elf_Addr sta
/* Add a segment that maps the new program/section headers and /* Add a segment that maps the new program/section headers and
PT_INTERP segment into memory. Otherwise glibc will choke. */ PT_INTERP segment into memory. Otherwise glibc will choke. */
phdrs.resize(rdi(hdr->e_phnum) + 1); phdrs.resize(rdi(hdr()->e_phnum) + 1);
wri(hdr->e_phnum, rdi(hdr->e_phnum) + 1); wri(hdr()->e_phnum, rdi(hdr()->e_phnum) + 1);
Elf_Phdr & phdr = phdrs[rdi(hdr->e_phnum) - 1]; Elf_Phdr & phdr = phdrs[rdi(hdr()->e_phnum) - 1];
wri(phdr.p_type, PT_LOAD); wri(phdr.p_type, PT_LOAD);
wri(phdr.p_offset, 0); wri(phdr.p_offset, 0);
wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage)); wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage));
@@ -658,7 +652,7 @@ Elf_Shdr * ElfFile<ElfFileParamNames>::findSection2(const SectionName & sectionN
template<ElfFileParams> template<ElfFileParams>
unsigned int ElfFile<ElfFileParamNames>::findSection3(const SectionName & sectionName) unsigned int ElfFile<ElfFileParamNames>::findSection3(const SectionName & sectionName)
{ {
for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i)
if (getSectionName(shdrs[i]) == sectionName) return i; if (getSectionName(shdrs[i]) == sectionName) return i;
return 0; return 0;
} }
@@ -680,7 +674,7 @@ std::string & ElfFile<ElfFileParamNames>::replaceSection(const SectionName & sec
s = std::string(i->second); s = std::string(i->second);
} else { } else {
auto shdr = findSection(sectionName); auto shdr = findSection(sectionName);
s = std::string((char *) contents + rdi(shdr.sh_offset), rdi(shdr.sh_size)); s = std::string((char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size));
} }
s.resize(size); s.resize(size);
@@ -701,7 +695,7 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
const std::string & sectionName = i.first; const std::string & sectionName = i.first;
Elf_Shdr & shdr = findSection(sectionName); Elf_Shdr & shdr = findSection(sectionName);
if (rdi(shdr.sh_type) != SHT_NOBITS) if (rdi(shdr.sh_type) != SHT_NOBITS)
memset(contents + rdi(shdr.sh_offset), 'X', rdi(shdr.sh_size)); memset(fileContents->data() + rdi(shdr.sh_offset), 'X', rdi(shdr.sh_size));
} }
std::set<unsigned int> noted_phdrs = {}; std::set<unsigned int> noted_phdrs = {};
@@ -712,7 +706,7 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
debug("rewriting section '%s' from offset 0x%x (size %d) to offset 0x%x (size %d)\n", debug("rewriting section '%s' from offset 0x%x (size %d) to offset 0x%x (size %d)\n",
sectionName.c_str(), rdi(shdr.sh_offset), rdi(shdr.sh_size), curOff, i.second.size()); sectionName.c_str(), rdi(shdr.sh_offset), rdi(shdr.sh_size), curOff, i.second.size());
memcpy(contents + curOff, (unsigned char *) i.second.c_str(), memcpy(fileContents->data() + curOff, (unsigned char *) i.second.c_str(),
i.second.size()); i.second.size());
/* Update the section header for this section. */ /* Update the section header for this section. */
@@ -831,7 +825,7 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
/* Some sections may already be replaced so account for that */ /* Some sections may already be replaced so account for that */
unsigned int i = 1; unsigned int i = 1;
Elf_Addr pht_size = sizeof(Elf_Ehdr) + (phdrs.size() + num_notes + 1)*sizeof(Elf_Phdr); Elf_Addr pht_size = sizeof(Elf_Ehdr) + (phdrs.size() + num_notes + 1)*sizeof(Elf_Phdr);
while( rdi(shdrs[i].sh_offset) <= pht_size && i < rdi(hdr->e_shnum) ) { while( rdi(shdrs[i].sh_offset) <= pht_size && i < rdi(hdr()->e_shnum) ) {
if (not haveReplacedSection(getSectionName(shdrs[i]))) if (not haveReplacedSection(getSectionName(shdrs[i])))
replaceSection(getSectionName(shdrs[i]), rdi(shdrs[i].sh_size)); replaceSection(getSectionName(shdrs[i]), rdi(shdrs[i].sh_size));
i++; i++;
@@ -845,7 +839,7 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
Elf_Off startOffset = roundUp(fileContents->size(), getPageSize()); Elf_Off startOffset = roundUp(fileContents->size(), getPageSize());
growFile(fileContents, startOffset + neededSpace); fileContents->resize(startOffset + neededSpace, 0);
/* Even though this file is of type ET_DYN, it could actually be /* Even though this file is of type ET_DYN, it could actually be
an executable. For instance, Gold produces executables marked an executable. For instance, Gold produces executables marked
@@ -867,10 +861,10 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
} }
/* Add a segment that maps the replaced sections into memory. */ /* Add a segment that maps the replaced sections into memory. */
wri(hdr->e_phoff, sizeof(Elf_Ehdr)); wri(hdr()->e_phoff, sizeof(Elf_Ehdr));
phdrs.resize(rdi(hdr->e_phnum) + 1); phdrs.resize(rdi(hdr()->e_phnum) + 1);
wri(hdr->e_phnum, rdi(hdr->e_phnum) + 1); wri(hdr()->e_phnum, rdi(hdr()->e_phnum) + 1);
Elf_Phdr & phdr = phdrs[rdi(hdr->e_phnum) - 1]; Elf_Phdr & phdr = phdrs[rdi(hdr()->e_phnum) - 1];
wri(phdr.p_type, PT_LOAD); wri(phdr.p_type, PT_LOAD);
wri(phdr.p_offset, startOffset); wri(phdr.p_offset, startOffset);
wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage)); wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage));
@@ -888,7 +882,7 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
assert(curOff == startOffset + neededSpace); assert(curOff == startOffset + neededSpace);
/* Write out the updated program and section headers */ /* Write out the updated program and section headers */
rewriteHeaders(firstPage + rdi(hdr->e_phoff)); rewriteHeaders(firstPage + rdi(hdr()->e_phoff));
} }
@@ -902,7 +896,7 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
/* What is the index of the last replaced section? */ /* What is the index of the last replaced section? */
unsigned int lastReplaced = 0; unsigned int lastReplaced = 0;
for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) { for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i) {
std::string sectionName = getSectionName(shdrs[i]); std::string sectionName = getSectionName(shdrs[i]);
if (replacedSections.count(sectionName)) { if (replacedSections.count(sectionName)) {
debug("using replaced section '%s'\n", sectionName.c_str()); debug("using replaced section '%s'\n", sectionName.c_str());
@@ -950,21 +944,21 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
Elf_Addr firstPage = startAddr - startOffset; Elf_Addr firstPage = startAddr - startOffset;
debug("first page is 0x%llx\n", (unsigned long long) firstPage); debug("first page is 0x%llx\n", (unsigned long long) firstPage);
if (rdi(hdr->e_shoff) < startOffset) { if (rdi(hdr()->e_shoff) < startOffset) {
/* The section headers occur too early in the file and would be /* 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 overwritten by the replaced sections. Move them to the end of the file
before proceeding. */ before proceeding. */
off_t shoffNew = fileContents->size(); off_t shoffNew = fileContents->size();
off_t shSize = rdi(hdr->e_shoff) + rdi(hdr->e_shnum) * rdi(hdr->e_shentsize); off_t shSize = rdi(hdr()->e_shoff) + rdi(hdr()->e_shnum) * rdi(hdr()->e_shentsize);
growFile(fileContents, fileContents->size() + shSize); fileContents->resize(fileContents->size() + shSize, 0);
wri(hdr->e_shoff, shoffNew); wri(hdr()->e_shoff, shoffNew);
/* Rewrite the section header table. For neatness, keep the /* Rewrite the section header table. For neatness, keep the
sections sorted. */ sections sorted. */
assert(rdi(hdr->e_shnum) == shdrs.size()); assert(rdi(hdr()->e_shnum) == shdrs.size());
sortShdrs(); sortShdrs();
for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i)
* ((Elf_Shdr *) (contents + rdi(hdr->e_shoff)) + i) = shdrs[i]; * ((Elf_Shdr *) (fileContents->data() + rdi(hdr()->e_shoff)) + i) = shdrs[i];
} }
@@ -1003,7 +997,7 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
/* Clear out the free space. */ /* Clear out the free space. */
Elf_Off curOff = sizeof(Elf_Ehdr) + phdrs.size() * sizeof(Elf_Phdr); Elf_Off curOff = sizeof(Elf_Ehdr) + phdrs.size() * sizeof(Elf_Phdr);
debug("clearing first %d bytes\n", startOffset - curOff); debug("clearing first %d bytes\n", startOffset - curOff);
memset(contents + curOff, 0, startOffset - curOff); memset(fileContents->data() + curOff, 0, startOffset - curOff);
/* Write out the replaced sections. */ /* Write out the replaced sections. */
@@ -1011,7 +1005,7 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
assert(curOff == neededSpace); assert(curOff == neededSpace);
rewriteHeaders(firstPage + rdi(hdr->e_phoff)); rewriteHeaders(firstPage + rdi(hdr()->e_phoff));
} }
@@ -1071,23 +1065,24 @@ void ElfFile<ElfFileParamNames>::normalizeNoteSegments()
} }
phdrs.insert(phdrs.end(), newPhdrs.begin(), newPhdrs.end()); phdrs.insert(phdrs.end(), newPhdrs.begin(), newPhdrs.end());
wri(hdr->e_phnum, phdrs.size()); wri(hdr()->e_phnum, phdrs.size());
} }
template<ElfFileParams> template<ElfFileParams>
void ElfFile<ElfFileParamNames>::rewriteSections() void ElfFile<ElfFileParamNames>::rewriteSections()
{ {
if (replacedSections.empty()) return; if (replacedSections.empty()) return;
for (auto & i : replacedSections) for (auto & i : replacedSections)
debug("replacing section '%s' with size %d\n", debug("replacing section '%s' with size %d\n",
i.first.c_str(), i.second.size()); i.first.c_str(), i.second.size());
if (rdi(hdr->e_type) == ET_DYN) { if (rdi(hdr()->e_type) == ET_DYN) {
debug("this is a dynamic library\n"); debug("this is a dynamic library\n");
rewriteSectionsLibrary(); rewriteSectionsLibrary();
} else if (rdi(hdr->e_type) == ET_EXEC) { } else if (rdi(hdr()->e_type) == ET_EXEC) {
debug("this is an executable\n"); debug("this is an executable\n");
rewriteSectionsExecutable(); rewriteSectionsExecutable();
} else error("unknown ELF type"); } else error("unknown ELF type");
@@ -1103,7 +1098,7 @@ void ElfFile<ElfFileParamNames>::rewriteHeaders(Elf_Addr phdrAddress)
(According to the ELF spec, there can only be one.) */ (According to the ELF spec, there can only be one.) */
for (auto & phdr : phdrs) { for (auto & phdr : phdrs) {
if (rdi(phdr.p_type) == PT_PHDR) { if (rdi(phdr.p_type) == PT_PHDR) {
phdr.p_offset = hdr->e_phoff; phdr.p_offset = hdr()->e_phoff;
wri(phdr.p_vaddr, wri(phdr.p_paddr, phdrAddress)); wri(phdr.p_vaddr, wri(phdr.p_paddr, phdrAddress));
wri(phdr.p_filesz, wri(phdr.p_memsz, phdrs.size() * sizeof(Elf_Phdr))); wri(phdr.p_filesz, wri(phdr.p_memsz, phdrs.size() * sizeof(Elf_Phdr)));
break; break;
@@ -1113,15 +1108,15 @@ void ElfFile<ElfFileParamNames>::rewriteHeaders(Elf_Addr phdrAddress)
sortPhdrs(); sortPhdrs();
for (unsigned int i = 0; i < phdrs.size(); ++i) for (unsigned int i = 0; i < phdrs.size(); ++i)
* ((Elf_Phdr *) (contents + rdi(hdr->e_phoff)) + i) = phdrs[i]; * ((Elf_Phdr *) (fileContents->data() + rdi(hdr()->e_phoff)) + i) = phdrs[i];
/* Rewrite the section header table. For neatness, keep the /* Rewrite the section header table. For neatness, keep the
sections sorted. */ sections sorted. */
assert(rdi(hdr->e_shnum) == shdrs.size()); assert(rdi(hdr()->e_shnum) == shdrs.size());
sortShdrs(); sortShdrs();
for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i)
* ((Elf_Shdr *) (contents + rdi(hdr->e_shoff)) + i) = shdrs[i]; * ((Elf_Shdr *) (fileContents->data() + rdi(hdr()->e_shoff)) + i) = shdrs[i];
/* Update all those nasty virtual addresses in the .dynamic /* Update all those nasty virtual addresses in the .dynamic
@@ -1129,7 +1124,7 @@ void ElfFile<ElfFileParamNames>::rewriteHeaders(Elf_Addr phdrAddress)
(e.g., those produced by klibc's klcc). */ (e.g., those produced by klibc's klcc). */
auto shdrDynamic = findSection2(".dynamic"); auto shdrDynamic = findSection2(".dynamic");
if (shdrDynamic) { if (shdrDynamic) {
auto dyn_table = (Elf_Dyn *) (contents + rdi(shdrDynamic->sh_offset)); auto dyn_table = (Elf_Dyn *) (fileContents->data() + rdi(shdrDynamic->sh_offset));
unsigned int d_tag; unsigned int d_tag;
for (auto dyn = dyn_table; (d_tag = rdi(dyn->d_tag)) != DT_NULL; dyn++) for (auto dyn = dyn_table; (d_tag = rdi(dyn->d_tag)) != DT_NULL; dyn++)
if (d_tag == DT_STRTAB) if (d_tag == DT_STRTAB)
@@ -1196,11 +1191,11 @@ void ElfFile<ElfFileParamNames>::rewriteHeaders(Elf_Addr phdrAddress)
/* Rewrite the .dynsym section. It contains the indices of the /* Rewrite the .dynsym section. It contains the indices of the
sections in which symbols appear, so these need to be sections in which symbols appear, so these need to be
remapped. */ remapped. */
for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) { for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i) {
if (rdi(shdrs[i].sh_type) != SHT_SYMTAB && rdi(shdrs[i].sh_type) != SHT_DYNSYM) continue; if (rdi(shdrs[i].sh_type) != SHT_SYMTAB && rdi(shdrs[i].sh_type) != SHT_DYNSYM) continue;
debug("rewriting symbol table section %d\n", i); debug("rewriting symbol table section %d\n", i);
for (size_t entry = 0; (entry + 1) * sizeof(Elf_Sym) <= rdi(shdrs[i].sh_size); entry++) { for (size_t entry = 0; (entry + 1) * sizeof(Elf_Sym) <= rdi(shdrs[i].sh_size); entry++) {
auto sym = (Elf_Sym *)(contents + rdi(shdrs[i].sh_offset) + entry * sizeof(Elf_Sym)); auto sym = (Elf_Sym *)(fileContents->data() + rdi(shdrs[i].sh_offset) + entry * sizeof(Elf_Sym));
unsigned int shndx = rdi(sym->st_shndx); unsigned int shndx = rdi(sym->st_shndx);
if (shndx != SHN_UNDEF && shndx < SHN_LORESERVE) { if (shndx != SHN_UNDEF && shndx < SHN_LORESERVE) {
if (shndx >= sectionsByOldIndex.size()) { if (shndx >= sectionsByOldIndex.size()) {
@@ -1234,23 +1229,23 @@ template<ElfFileParams>
std::string ElfFile<ElfFileParamNames>::getInterpreter() std::string ElfFile<ElfFileParamNames>::getInterpreter()
{ {
auto shdr = findSection(".interp"); auto shdr = findSection(".interp");
return std::string((char *) contents + rdi(shdr.sh_offset), rdi(shdr.sh_size)); return std::string((char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size));
} }
template<ElfFileParams> template<ElfFileParams>
void ElfFile<ElfFileParamNames>::modifySoname(sonameMode op, const std::string & newSoname) void ElfFile<ElfFileParamNames>::modifySoname(sonameMode op, const std::string & newSoname)
{ {
if (rdi(hdr->e_type) != ET_DYN) { if (rdi(hdr()->e_type) != ET_DYN) {
debug("this is not a dynamic library\n"); debug("this is not a dynamic library\n");
return; return;
} }
auto shdrDynamic = findSection(".dynamic"); auto shdrDynamic = findSection(".dynamic");
auto shdrDynStr = findSection(".dynstr"); auto shdrDynStr = findSection(".dynstr");
char * strTab = (char *) contents + rdi(shdrDynStr.sh_offset); char * strTab = (char *) fileContents->data() + rdi(shdrDynStr.sh_offset);
/* Walk through the dynamic section, look for the DT_SONAME entry. */ /* Walk through the dynamic section, look for the DT_SONAME entry. */
auto dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic.sh_offset)); auto dyn = (Elf_Dyn *)(fileContents->data() + rdi(shdrDynamic.sh_offset));
Elf_Dyn * dynSoname = nullptr; Elf_Dyn * dynSoname = nullptr;
char * soname = nullptr; char * soname = nullptr;
for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) { for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) {
@@ -1357,7 +1352,7 @@ std::string ElfFile<ElfFileParamNames>::shrinkRPath(char* rpath, std::vector<std
std::string libName = dirName + "/" + neededLibs[j]; std::string libName = dirName + "/" + neededLibs[j];
try { try {
Elf32_Half library_e_machine = getElfType(readFile(libName, sizeof(Elf32_Ehdr))).machine; Elf32_Half library_e_machine = getElfType(readFile(libName, sizeof(Elf32_Ehdr))).machine;
if (rdi(library_e_machine) == rdi(hdr->e_machine)) { if (rdi(library_e_machine) == rdi(hdr()->e_machine)) {
neededLibFound[j] = true; neededLibFound[j] = true;
libFound = true; libFound = true;
} else } else
@@ -1378,7 +1373,7 @@ std::string ElfFile<ElfFileParamNames>::shrinkRPath(char* rpath, std::vector<std
template<ElfFileParams> template<ElfFileParams>
void ElfFile<ElfFileParamNames>::removeRPath(Elf_Shdr & shdrDynamic) { void ElfFile<ElfFileParamNames>::removeRPath(Elf_Shdr & shdrDynamic) {
auto dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic.sh_offset)); auto dyn = (Elf_Dyn *)(fileContents->data() + rdi(shdrDynamic.sh_offset));
Elf_Dyn * last = dyn; Elf_Dyn * last = dyn;
for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) { for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) {
if (rdi(dyn->d_tag) == DT_RPATH) { if (rdi(dyn->d_tag) == DT_RPATH) {
@@ -1408,7 +1403,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
/* !!! We assume that the virtual address in the DT_STRTAB entry /* !!! We assume that the virtual address in the DT_STRTAB entry
of the dynamic section corresponds to the .dynstr section. */ of the dynamic section corresponds to the .dynstr section. */
auto shdrDynStr = findSection(".dynstr"); auto shdrDynStr = findSection(".dynstr");
char * strTab = (char *) contents + rdi(shdrDynStr.sh_offset); char * strTab = (char *) fileContents->data() + rdi(shdrDynStr.sh_offset);
/* Walk through the dynamic section, look for the RPATH/RUNPATH /* Walk through the dynamic section, look for the RPATH/RUNPATH
@@ -1424,7 +1419,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
generates a DT_RPATH and DT_RUNPATH pointing at the same generates a DT_RPATH and DT_RUNPATH pointing at the same
string. */ string. */
std::vector<std::string> neededLibs; std::vector<std::string> neededLibs;
auto dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic.sh_offset)); auto dyn = (Elf_Dyn *)(fileContents->data() + rdi(shdrDynamic.sh_offset));
Elf_Dyn *dynRPath = nullptr, *dynRunPath = nullptr; Elf_Dyn *dynRPath = nullptr, *dynRunPath = nullptr;
char * rpath = nullptr; char * rpath = nullptr;
for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) { for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) {
@@ -1548,9 +1543,9 @@ void ElfFile<ElfFileParamNames>::removeNeeded(const std::set<std::string> & libs
auto shdrDynamic = findSection(".dynamic"); auto shdrDynamic = findSection(".dynamic");
auto shdrDynStr = findSection(".dynstr"); auto shdrDynStr = findSection(".dynstr");
char * strTab = (char *) contents + rdi(shdrDynStr.sh_offset); char * strTab = (char *) fileContents->data() + rdi(shdrDynStr.sh_offset);
auto dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic.sh_offset)); auto dyn = (Elf_Dyn *)(fileContents->data() + rdi(shdrDynamic.sh_offset));
Elf_Dyn * last = dyn; Elf_Dyn * last = dyn;
for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) { for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) {
if (rdi(dyn->d_tag) == DT_NEEDED) { if (rdi(dyn->d_tag) == DT_NEEDED) {
@@ -1576,9 +1571,9 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std::
auto shdrDynamic = findSection(".dynamic"); auto shdrDynamic = findSection(".dynamic");
auto shdrDynStr = findSection(".dynstr"); auto shdrDynStr = findSection(".dynstr");
char * strTab = (char *) contents + rdi(shdrDynStr.sh_offset); char * strTab = (char *) fileContents->data() + rdi(shdrDynStr.sh_offset);
auto dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic.sh_offset)); auto dyn = (Elf_Dyn *)(fileContents->data() + rdi(shdrDynamic.sh_offset));
unsigned int verNeedNum = 0; unsigned int verNeedNum = 0;
@@ -1627,7 +1622,7 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std::
// which one. // which one.
Elf_Shdr & shdrVersionRStrings = shdrs[rdi(shdrVersionR.sh_link)]; Elf_Shdr & shdrVersionRStrings = shdrs[rdi(shdrVersionR.sh_link)];
// this is where we find the actual filename strings // this is where we find the actual filename strings
char * verStrTab = (char *) contents + rdi(shdrVersionRStrings.sh_offset); char * verStrTab = (char *) fileContents->data() + rdi(shdrVersionRStrings.sh_offset);
// and we also need the name of the section containing the strings, so // and we also need the name of the section containing the strings, so
// that we can pass it to replaceSection // that we can pass it to replaceSection
std::string versionRStringsSName = getSectionName(shdrVersionRStrings); std::string versionRStringsSName = getSectionName(shdrVersionRStrings);
@@ -1636,7 +1631,7 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std::
unsigned int verStrAddedBytes = 0; unsigned int verStrAddedBytes = 0;
auto need = (Elf_Verneed *)(contents + rdi(shdrVersionR.sh_offset)); auto need = (Elf_Verneed *)(fileContents->data() + rdi(shdrVersionR.sh_offset));
while (verNeedNum > 0) { while (verNeedNum > 0) {
char * file = verStrTab + rdi(need->vn_file); char * file = verStrTab + rdi(need->vn_file);
auto i = libs.find(file); auto i = libs.find(file);
@@ -1720,9 +1715,9 @@ void ElfFile<ElfFileParamNames>::printNeededLibs() // const
{ {
const auto shdrDynamic = findSection(".dynamic"); const auto shdrDynamic = findSection(".dynamic");
const auto shdrDynStr = findSection(".dynstr"); const auto shdrDynStr = findSection(".dynstr");
const char *strTab = (char *)contents + rdi(shdrDynStr.sh_offset); const char *strTab = (char *)fileContents->data() + rdi(shdrDynStr.sh_offset);
const Elf_Dyn *dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset)); const Elf_Dyn *dyn = (Elf_Dyn *) (fileContents->data() + rdi(shdrDynamic.sh_offset));
for (; rdi(dyn->d_tag) != DT_NULL; dyn++) { for (; rdi(dyn->d_tag) != DT_NULL; dyn++) {
if (rdi(dyn->d_tag) == DT_NEEDED) { if (rdi(dyn->d_tag) == DT_NEEDED) {
@@ -1738,7 +1733,7 @@ void ElfFile<ElfFileParamNames>::noDefaultLib()
{ {
auto shdrDynamic = findSection(".dynamic"); auto shdrDynamic = findSection(".dynamic");
auto dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic.sh_offset)); auto dyn = (Elf_Dyn *)(fileContents->data() + rdi(shdrDynamic.sh_offset));
auto dynFlags1 = (Elf_Dyn *)nullptr; auto dynFlags1 = (Elf_Dyn *)nullptr;
for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) { for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) {
if (rdi(dyn->d_tag) == DT_FLAGS_1) { if (rdi(dyn->d_tag) == DT_FLAGS_1) {
@@ -1781,9 +1776,9 @@ void ElfFile<ElfFileParamNames>::clearSymbolVersions(const std::set<std::string>
auto shdrDynsym = findSection(".dynsym"); auto shdrDynsym = findSection(".dynsym");
auto shdrVersym = findSection(".gnu.version"); auto shdrVersym = findSection(".gnu.version");
auto strTab = (char *)contents + rdi(shdrDynStr.sh_offset); auto strTab = (char *)fileContents->data() + rdi(shdrDynStr.sh_offset);
auto dynsyms = (Elf_Sym *)(contents + rdi(shdrDynsym.sh_offset)); auto dynsyms = (Elf_Sym *)(fileContents->data() + rdi(shdrDynsym.sh_offset));
auto versyms = (Elf_Versym *)(contents + rdi(shdrVersym.sh_offset)); auto versyms = (Elf_Versym *)(fileContents->data() + rdi(shdrVersym.sh_offset));
size_t count = rdi(shdrDynsym.sh_size) / sizeof(Elf_Sym); size_t count = rdi(shdrDynsym.sh_size) / sizeof(Elf_Sym);
if (count != rdi(shdrVersym.sh_size) / sizeof(Elf_Versym)) if (count != rdi(shdrVersym.sh_size) / sizeof(Elf_Versym))

View File

@@ -2,7 +2,7 @@ LIBS =
STRIP ?= strip STRIP ?= strip
check_PROGRAMS = simple main too-many-strtab main-scoped big-dynstr no-rpath contiguous-note-sections check_PROGRAMS = simple-pie simple main too-many-strtab main-scoped big-dynstr no-rpath contiguous-note-sections
no_rpath_arch_TESTS = \ no_rpath_arch_TESTS = \
no-rpath-amd64.sh \ no-rpath-amd64.sh \
@@ -35,6 +35,7 @@ src_TESTS = \
endianness.sh \ endianness.sh \
contiguous-note-sections.sh \ contiguous-note-sections.sh \
no-gnu-hash.sh \ no-gnu-hash.sh \
grow-file.sh \
no-dynamic-section.sh \ no-dynamic-section.sh \
args-from-file.sh \ args-from-file.sh \
basic-flags.sh \ basic-flags.sh \
@@ -67,6 +68,9 @@ simple_SOURCES = simple.c
# no -fpic for simple.o # no -fpic for simple.o
simple_CFLAGS = simple_CFLAGS =
simple_pie_SOURCES = simple.c
simple_pie_CFLAGS = -fPIC -pie
main_SOURCES = main.c main_SOURCES = main.c
main_LDADD = -lfoo $(AM_LDADD) main_LDADD = -lfoo $(AM_LDADD)
main_DEPENDENCIES = libfoo.so main_DEPENDENCIES = libfoo.so

16
tests/grow-file.sh Executable file
View File

@@ -0,0 +1,16 @@
#! /bin/sh -e
SCRATCH=scratch/$(basename $0 .sh)
rm -rf ${SCRATCH}
mkdir -p ${SCRATCH}
cp simple-pie ${SCRATCH}/simple-pie
# Add a 40MB rpath
head -c 40000000 /dev/urandom > ${SCRATCH}/foo.bin
# Grow the file
../src/patchelf --add-rpath @${SCRATCH}/foo.bin ${SCRATCH}/simple-pie
# Make sure we can still run it
${SCRATCH}/simple-pie