[ELF] Correctly compute .gdb_index size when symbol's name offset overflows

if `nameOff` overflows, `size` may be underestimated.
In writeTo, `memcpy(buf + sym.nameOff, sym.name.data(), sym.name.size());` may
cause an out-of-bounds write, leading to a SIGSEGV.
This commit is contained in:
Fangrui Song
2022-08-31 21:04:26 -07:00
parent 6e47ebdcec
commit 7a20d6abe4
2 changed files with 11 additions and 19 deletions

View File

@@ -2692,20 +2692,6 @@ size_t GdbIndexSection::computeSymtabSize() const {
return std::max<size_t>(NextPowerOf2(symbols.size() * 4 / 3), 1024);
}
// Compute the output section size.
void GdbIndexSection::initOutputSize() {
size = sizeof(GdbIndexHeader) + computeSymtabSize() * 8;
for (GdbChunk &chunk : chunks)
size += chunk.compilationUnits.size() * 16 + chunk.addressAreas.size() * 20;
// Add the constant pool size if exists.
if (!symbols.empty()) {
GdbSymbol &sym = symbols.back();
size += sym.nameOff + sym.name.size() + 1;
}
}
static SmallVector<GdbIndexSection::CuEntry, 0>
readCuList(DWARFContext &dwarf) {
SmallVector<GdbIndexSection::CuEntry, 0> ret;
@@ -2780,7 +2766,8 @@ readPubNamesAndTypes(const LLDDwarfObj<ELFT> &obj,
// Create a list of symbols from a given list of symbol names and types
// by uniquifying them by name.
static SmallVector<GdbIndexSection::GdbSymbol, 0> createSymbols(
static std::pair<SmallVector<GdbIndexSection::GdbSymbol, 0>, size_t>
createSymbols(
ArrayRef<SmallVector<GdbIndexSection::NameAttrEntry, 0>> nameAttrs,
const SmallVector<GdbIndexSection::GdbChunk, 0> &chunks) {
using GdbSymbol = GdbIndexSection::GdbSymbol;
@@ -2858,7 +2845,7 @@ static SmallVector<GdbIndexSection::GdbSymbol, 0> createSymbols(
off += sym.name.size() + 1;
}
return ret;
return {ret, off};
}
// Returns a newly-created .gdb_index section.
@@ -2908,8 +2895,14 @@ template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
auto *ret = make<GdbIndexSection>();
ret->chunks = std::move(chunks);
ret->symbols = createSymbols(nameAttrs, ret->chunks);
ret->initOutputSize();
std::tie(ret->symbols, ret->size) = createSymbols(nameAttrs, ret->chunks);
// Count the areas other than the constant pool.
ret->size += sizeof(GdbIndexHeader) + ret->computeSymtabSize() * 8;
for (GdbChunk &chunk : ret->chunks)
ret->size +=
chunk.compilationUnits.size() * 16 + chunk.addressAreas.size() * 20;
return ret;
}

View File

@@ -787,7 +787,6 @@ private:
llvm::support::ulittle32_t constantPoolOff;
};
void initOutputSize();
size_t computeSymtabSize() const;
// Each chunk contains information gathered from debug sections of a