Skip to content

Commit 65bf3d9

Browse files
bors[bot]brenoguimMic92
authored
Merge #460
460: Avoid overlapping program header table with section header table #457 r=Mic92 a=brenoguim Co-authored-by: Breno Rodrigues Guimaraes <[email protected]> Co-authored-by: Breno Rodrigues Guimarães <[email protected]> Co-authored-by: Jörg Thalheim <[email protected]>
2 parents 69a7ae5 + eb9ea00 commit 65bf3d9

File tree

3 files changed

+79
-10
lines changed

3 files changed

+79
-10
lines changed

src/patchelf.cc

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -826,11 +826,16 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
826826
replaceSection(getSectionName(shdrs.at(i)), rdi(shdrs.at(i).sh_size));
827827
i++;
828828
}
829+
bool moveHeaderTableToTheEnd = rdi(hdr()->e_shoff) < pht_size;
829830

830831
/* Compute the total space needed for the replaced sections */
831832
off_t neededSpace = 0;
832833
for (auto & s : replacedSections)
833834
neededSpace += roundUp(s.second.size(), sectionAlignment);
835+
836+
off_t headerTableSpace = roundUp(rdi(hdr()->e_shnum) * rdi(hdr()->e_shentsize), sectionAlignment);
837+
if (moveHeaderTableToTheEnd)
838+
neededSpace += headerTableSpace;
834839
debug("needed space is %d\n", neededSpace);
835840

836841
Elf_Off startOffset = roundUp(fileContents->size(), getPageSize());
@@ -860,24 +865,48 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
860865
startPage = startOffset;
861866
}
862867

863-
/* Add a segment that maps the replaced sections into memory. */
864868
wri(hdr()->e_phoff, sizeof(Elf_Ehdr));
865-
phdrs.resize(rdi(hdr()->e_phnum) + 1);
866-
wri(hdr()->e_phnum, rdi(hdr()->e_phnum) + 1);
867-
Elf_Phdr & phdr = phdrs.at(rdi(hdr()->e_phnum) - 1);
868-
wri(phdr.p_type, PT_LOAD);
869-
wri(phdr.p_offset, startOffset);
870-
wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage));
871-
wri(phdr.p_filesz, wri(phdr.p_memsz, neededSpace));
872-
wri(phdr.p_flags, PF_R | PF_W);
873-
wri(phdr.p_align, getPageSize());
874869

870+
bool needNewSegment = true;
871+
auto& lastSeg = phdrs.back();
872+
/* Try to extend the last segment to include replaced sections */
873+
if (!phdrs.empty() &&
874+
rdi(lastSeg.p_type) == PT_LOAD &&
875+
rdi(lastSeg.p_flags) == (PF_R | PF_W) &&
876+
rdi(lastSeg.p_align) == getPageSize()) {
877+
auto segEnd = roundUp(rdi(lastSeg.p_offset) + rdi(lastSeg.p_memsz), getPageSize());
878+
if (segEnd == startOffset) {
879+
auto newSz = startOffset + neededSpace - rdi(lastSeg.p_offset);
880+
wri(lastSeg.p_filesz, wri(lastSeg.p_memsz, newSz));
881+
needNewSegment = false;
882+
}
883+
}
884+
885+
if (needNewSegment) {
886+
/* Add a segment that maps the replaced sections into memory. */
887+
phdrs.resize(rdi(hdr()->e_phnum) + 1);
888+
wri(hdr()->e_phnum, rdi(hdr()->e_phnum) + 1);
889+
Elf_Phdr & phdr = phdrs.at(rdi(hdr()->e_phnum) - 1);
890+
wri(phdr.p_type, PT_LOAD);
891+
wri(phdr.p_offset, startOffset);
892+
wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage));
893+
wri(phdr.p_filesz, wri(phdr.p_memsz, neededSpace));
894+
wri(phdr.p_flags, PF_R | PF_W);
895+
wri(phdr.p_align, getPageSize());
896+
}
875897

876898
normalizeNoteSegments();
877899

878900

879901
/* Write out the replaced sections. */
880902
Elf_Off curOff = startOffset;
903+
904+
if (moveHeaderTableToTheEnd) {
905+
debug("Moving the shtable to offset %d\n", curOff);
906+
wri(hdr()->e_shoff, curOff);
907+
curOff += headerTableSpace;
908+
}
909+
881910
writeReplacedSections(curOff, startPage, startOffset);
882911
assert(curOff == startOffset + neededSpace);
883912

tests/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ src_TESTS = \
4343
replace-needed.sh \
4444
replace-add-needed.sh \
4545
add-debug-tag.sh \
46+
repeated-updates.sh \
4647
empty-note.sh \
4748
print-execstack.sh \
4849
modify-execstack.sh \

tests/repeated-updates.sh

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#! /bin/sh -e
2+
3+
SCRATCH=scratch/$(basename "$0" .sh)
4+
PATCHELF=$(readlink -f "../src/patchelf")
5+
6+
rm -rf "${SCRATCH}"
7+
mkdir -p "${SCRATCH}"
8+
9+
cp simple "${SCRATCH}/"
10+
cp libfoo.so "${SCRATCH}/"
11+
cp libbar.so "${SCRATCH}/"
12+
13+
cd "${SCRATCH}"
14+
15+
${PATCHELF} --add-needed ./libbar.so simple
16+
17+
###############################################################################
18+
# Test that repeatedly modifying a string inside a shared library does not
19+
# corrupt it due to the addition of multiple PT_LOAD entries
20+
###############################################################################
21+
load_segments_before=$(readelf -W -l libbar.so | grep -c LOAD)
22+
23+
for _ in $(seq 1 100)
24+
do
25+
${PATCHELF} --set-soname ./libbar.so libbar.so
26+
${PATCHELF} --set-soname libbar.so libbar.so
27+
./simple || exit 1
28+
done
29+
30+
load_segments_after=$(readelf -W -l libbar.so | grep -c LOAD)
31+
32+
###############################################################################
33+
# To be even more strict, check that we don't add too many extra LOAD entries
34+
###############################################################################
35+
echo "Segments before: ${load_segments_before} and after: ${load_segments_after}"
36+
if [ "${load_segments_after}" -gt $((load_segments_before + 2)) ]
37+
then
38+
exit 1
39+
fi

0 commit comments

Comments
 (0)