diff options
author | Fangrui Song <i@maskray.me> | 2021-05-05 10:26:57 -0700 |
---|---|---|
committer | Fangrui Song <i@maskray.me> | 2021-05-05 10:26:57 -0700 |
commit | b3336bfa2e6a38f16c4ecf4d77bd0f97ec5a46eb (patch) | |
tree | 76189759352b4c638793e3d859569be328570dd8 /llvm/tools/llvm-objcopy/ELF/Object.cpp | |
parent | ba5c122647c79586a6d060ca649e586feb7f57a0 (diff) | |
download | llvm-b3336bfa2e6a38f16c4ecf4d77bd0f97ec5a46eb.zip llvm-b3336bfa2e6a38f16c4ecf4d77bd0f97ec5a46eb.tar.gz llvm-b3336bfa2e6a38f16c4ecf4d77bd0f97ec5a46eb.tar.bz2 |
[llvm-objcopy][ELF] --only-keep-debug: set offset/size of segments with no sections to zero
PR50160: we currently ignore non-PT_PHDR segments with no sections, not
accounting for its p_offset and p_filesz: this can cause an out-of-bounds write
in `writeSegmentData` if the p_offset+p_filesz is larger than the total file
size.
This can be fixed by setting p_offset=p_filesz=0. The logic nicely unifies with
the logic added in D90897.
Reviewed By: jhenderson, rupprecht
Differential Revision: https://reviews.llvm.org/D101560
Diffstat (limited to 'llvm/tools/llvm-objcopy/ELF/Object.cpp')
-rw-r--r-- | llvm/tools/llvm-objcopy/ELF/Object.cpp | 21 |
1 files changed, 11 insertions, 10 deletions
diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp index a8bd135..0ac8b3a 100644 --- a/llvm/tools/llvm-objcopy/ELF/Object.cpp +++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -2315,18 +2315,19 @@ static uint64_t layoutSegmentsForOnlyKeepDebug(std::vector<Segment *> &Segments, uint64_t HdrEnd) { uint64_t MaxOffset = 0; for (Segment *Seg : Segments) { - // An empty segment contains no section (see sectionWithinSegment). If it - // has a parent segment, copy the parent segment's offset field. This works - // for empty PT_TLS. We don't handle empty segments without a parent for - // now. - if (Seg->ParentSegment != nullptr && Seg->MemSize == 0) - Seg->Offset = Seg->ParentSegment->Offset; - - const SectionBase *FirstSec = Seg->firstSection(); - if (Seg->Type == PT_PHDR || !FirstSec) + if (Seg->Type == PT_PHDR) continue; - uint64_t Offset = FirstSec->Offset; + // The segment offset is generally the offset of the first section. + // + // For a segment containing no section (see sectionWithinSegment), if it has + // a parent segment, copy the parent segment's offset field. This works for + // empty PT_TLS. If no parent segment, use 0: the segment is not useful for + // debugging anyway. + const SectionBase *FirstSec = Seg->firstSection(); + uint64_t Offset = + FirstSec ? FirstSec->Offset + : (Seg->ParentSegment ? Seg->ParentSegment->Offset : 0); uint64_t FileSize = 0; for (const SectionBase *Sec : Seg->Sections) { uint64_t Size = Sec->Type == SHT_NOBITS ? 0 : Sec->Size; |