Skip to content

Commit af77f12

Browse files
authored
Merge pull request #415 from Bo98/load-overlap-fix
Rework file shifting to avoid sections crossing multiple segments
2 parents ec72eeb + 109b771 commit af77f12

File tree

2 files changed

+59
-21
lines changed

2 files changed

+59
-21
lines changed

src/patchelf.cc

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -432,44 +432,83 @@ static uint64_t roundUp(uint64_t n, uint64_t m)
432432

433433

434434
template<ElfFileParams>
435-
void ElfFile<ElfFileParamNames>::shiftFile(unsigned int extraPages, Elf_Addr startPage)
435+
void ElfFile<ElfFileParamNames>::shiftFile(unsigned int extraPages, size_t startOffset)
436436
{
437-
/* Move the entire contents of the file 'extraPages' pages
438-
further. */
437+
assert(startOffset >= sizeof(Elf_Ehdr));
438+
439439
unsigned int oldSize = fileContents->size();
440+
assert(oldSize > startOffset);
441+
442+
/* Move the entire contents of the file after 'startOffset' by 'extraPages' pages further. */
440443
unsigned int shift = extraPages * getPageSize();
441444
fileContents->resize(oldSize + shift, 0);
442-
memmove(fileContents->data() + shift, fileContents->data(), oldSize);
443-
memset(fileContents->data() + sizeof(Elf_Ehdr), 0, shift - sizeof(Elf_Ehdr));
445+
memmove(fileContents->data() + startOffset + shift, fileContents->data() + startOffset, oldSize - startOffset);
446+
memset(fileContents->data() + startOffset, 0, shift);
444447

445448
/* Adjust the ELF header. */
446449
wri(hdr()->e_phoff, sizeof(Elf_Ehdr));
447-
wri(hdr()->e_shoff, rdi(hdr()->e_shoff) + shift);
450+
if (rdi(hdr()->e_shoff) >= startOffset)
451+
wri(hdr()->e_shoff, rdi(hdr()->e_shoff) + shift);
448452

449453
/* Update the offsets in the section headers. */
450-
for (int i = 1; i < rdi(hdr()->e_shnum); ++i)
451-
wri(shdrs.at(i).sh_offset, rdi(shdrs.at(i).sh_offset) + shift);
454+
for (int i = 1; i < rdi(hdr()->e_shnum); ++i) {
455+
size_t sh_offset = rdi(shdrs.at(i).sh_offset);
456+
if (sh_offset >= startOffset)
457+
wri(shdrs.at(i).sh_offset, sh_offset + shift);
458+
}
459+
460+
int splitIndex = -1;
461+
size_t splitShift = 0;
452462

453463
/* Update the offsets in the program headers. */
454464
for (int i = 0; i < rdi(hdr()->e_phnum); ++i) {
455-
wri(phdrs.at(i).p_offset, rdi(phdrs.at(i).p_offset) + shift);
456-
if (rdi(phdrs.at(i).p_align) != 0 &&
457-
(rdi(phdrs.at(i).p_vaddr) - rdi(phdrs.at(i).p_offset)) % rdi(phdrs.at(i).p_align) != 0) {
458-
debug("changing alignment of program header %d from %d to %d\n", i,
459-
rdi(phdrs.at(i).p_align), getPageSize());
460-
wri(phdrs.at(i).p_align, getPageSize());
465+
Elf_Off p_start = rdi(phdrs.at(i).p_offset);
466+
467+
if (p_start <= startOffset && p_start + rdi(phdrs.at(i).p_filesz) > startOffset && rdi(phdrs.at(i).p_type) == PT_LOAD) {
468+
assert(splitIndex == -1);
469+
470+
splitIndex = i;
471+
splitShift = startOffset - p_start;
472+
473+
/* This is the load segment we're currently extending within, so we split it. */
474+
wri(phdrs.at(i).p_offset, startOffset);
475+
wri(phdrs.at(i).p_memsz, rdi(phdrs.at(i).p_memsz) - splitShift);
476+
wri(phdrs.at(i).p_filesz, rdi(phdrs.at(i).p_filesz) - splitShift);
477+
wri(phdrs.at(i).p_paddr, rdi(phdrs.at(i).p_paddr) + splitShift);
478+
wri(phdrs.at(i).p_vaddr, rdi(phdrs.at(i).p_vaddr) + splitShift);
479+
480+
p_start = startOffset;
481+
}
482+
483+
if (p_start >= startOffset) {
484+
wri(phdrs.at(i).p_offset, p_start + shift);
485+
if (rdi(phdrs.at(i).p_align) != 0 &&
486+
(rdi(phdrs.at(i).p_vaddr) - rdi(phdrs.at(i).p_offset)) % rdi(phdrs.at(i).p_align) != 0) {
487+
debug("changing alignment of program header %d from %d to %d\n", i,
488+
rdi(phdrs.at(i).p_align), getPageSize());
489+
wri(phdrs.at(i).p_align, getPageSize());
490+
}
491+
} else {
492+
/* If we're not physically shifting, shift back virtual memory. */
493+
if (rdi(phdrs.at(i).p_paddr) >= shift)
494+
wri(phdrs.at(i).p_paddr, rdi(phdrs.at(i).p_paddr) - shift);
495+
if (rdi(phdrs.at(i).p_vaddr) >= shift)
496+
wri(phdrs.at(i).p_vaddr, rdi(phdrs.at(i).p_vaddr) - shift);
461497
}
462498
}
463499

500+
assert(splitIndex != -1);
501+
464502
/* Add a segment that maps the new program/section headers and
465503
PT_INTERP segment into memory. Otherwise glibc will choke. */
466504
phdrs.resize(rdi(hdr()->e_phnum) + 1);
467505
wri(hdr()->e_phnum, rdi(hdr()->e_phnum) + 1);
468506
Elf_Phdr & phdr = phdrs.at(rdi(hdr()->e_phnum) - 1);
469507
wri(phdr.p_type, PT_LOAD);
470-
wri(phdr.p_offset, 0);
471-
wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage));
472-
wri(phdr.p_filesz, wri(phdr.p_memsz, shift));
508+
wri(phdr.p_offset, phdrs.at(splitIndex).p_offset - splitShift - shift);
509+
wri(phdr.p_paddr, phdrs.at(splitIndex).p_paddr - splitShift - shift);
510+
wri(phdr.p_vaddr, phdrs.at(splitIndex).p_vaddr - splitShift - shift);
511+
wri(phdr.p_filesz, wri(phdr.p_memsz, splitShift + shift));
473512
wri(phdr.p_flags, PF_R | PF_W);
474513
wri(phdr.p_align, getPageSize());
475514
}
@@ -855,7 +894,6 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
855894
file by the minimum number of pages and adjust internal
856895
offsets. */
857896
if (neededSpace > startOffset) {
858-
859897
/* We also need an additional program header, so adjust for that. */
860898
neededSpace += sizeof(Elf_Phdr);
861899
debug("needed space is %d\n", neededSpace);
@@ -865,10 +903,10 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
865903
if (neededPages * getPageSize() > firstPage)
866904
error("virtual address space underrun!");
867905

906+
shiftFile(neededPages, startOffset);
907+
868908
firstPage -= neededPages * getPageSize();
869909
startOffset += neededPages * getPageSize();
870-
871-
shiftFile(neededPages, firstPage);
872910
}
873911

874912

src/patchelf.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class ElfFile
7777

7878
void sortShdrs();
7979

80-
void shiftFile(unsigned int extraPages, Elf_Addr startPage);
80+
void shiftFile(unsigned int extraPages, size_t sizeOffset);
8181

8282
std::string getSectionName(const Elf_Shdr & shdr) const;
8383

0 commit comments

Comments
 (0)