[DWARF] Better detect errors in Address Range Tables.

The patch tries to cover most remaining cases of wrong data.

Differential Revision: https://reviews.llvm.org/D71932
This commit is contained in:
Igor Kudrin 2019-12-26 19:53:06 +07:00
parent 6332990721
commit ed9851a0a6
2 changed files with 154 additions and 11 deletions

View File

@ -59,9 +59,31 @@ Error DWARFDebugArangeSet::extract(DataExtractor data, uint64_t *offset_ptr) {
// the segment selectors are omitted from all tuples, including // the segment selectors are omitted from all tuples, including
// the terminating tuple. // the terminating tuple.
constexpr unsigned CommonFieldsLength = 2 + // Version
1 + // Address Size
1; // Segment Selector Size
constexpr unsigned DWARF32HeaderLength =
dwarf::getUnitLengthFieldByteSize(dwarf::DWARF32) + CommonFieldsLength +
dwarf::getDwarfOffsetByteSize(dwarf::DWARF32); // Debug Info Offset
constexpr unsigned DWARF64HeaderLength =
dwarf::getUnitLengthFieldByteSize(dwarf::DWARF64) + CommonFieldsLength +
dwarf::getDwarfOffsetByteSize(dwarf::DWARF64); // Debug Info Offset
if (!data.isValidOffsetForDataOfSize(Offset, DWARF32HeaderLength))
return createStringError(errc::invalid_argument,
"section is not large enough to contain "
"an address range table at offset 0x%" PRIx64,
Offset);
dwarf::DwarfFormat format = dwarf::DWARF32; dwarf::DwarfFormat format = dwarf::DWARF32;
HeaderData.Length = data.getU32(offset_ptr); HeaderData.Length = data.getU32(offset_ptr);
if (HeaderData.Length == dwarf::DW_LENGTH_DWARF64) { if (HeaderData.Length == dwarf::DW_LENGTH_DWARF64) {
if (!data.isValidOffsetForDataOfSize(Offset, DWARF64HeaderLength))
return createStringError(
errc::invalid_argument,
"section is not large enough to contain a DWARF64 "
"address range table at offset 0x%" PRIx64,
Offset);
HeaderData.Length = data.getU64(offset_ptr); HeaderData.Length = data.getU64(offset_ptr);
format = dwarf::DWARF64; format = dwarf::DWARF64;
} else if (HeaderData.Length >= dwarf::DW_LENGTH_lo_reserved) { } else if (HeaderData.Length >= dwarf::DW_LENGTH_lo_reserved) {
@ -91,17 +113,38 @@ Error DWARFDebugArangeSet::extract(DataExtractor data, uint64_t *offset_ptr) {
" has unsupported address size: %d " " has unsupported address size: %d "
"(4 and 8 supported)", "(4 and 8 supported)",
Offset, HeaderData.AddrSize); Offset, HeaderData.AddrSize);
if (HeaderData.SegSize != 0)
return createStringError(errc::not_supported,
"non-zero segment selector size in address range "
"table at offset 0x%" PRIx64 " is not supported",
Offset);
// The first tuple following the header in each set begins at an offset // The first tuple following the header in each set begins at an offset that
// that is a multiple of the size of a single tuple (that is, twice the // is a multiple of the size of a single tuple (that is, twice the size of
// size of an address). The header is padded, if necessary, to the // an address because we do not support non-zero segment selector sizes).
// appropriate boundary. // Therefore, the full length should also be a multiple of the tuple size.
const uint32_t header_size = *offset_ptr - Offset;
const uint32_t tuple_size = HeaderData.AddrSize * 2; const uint32_t tuple_size = HeaderData.AddrSize * 2;
if (full_length % tuple_size != 0)
return createStringError(
errc::invalid_argument,
"address range table at offset 0x%" PRIx64
" has length that is not a multiple of the tuple size",
Offset);
// The header is padded, if necessary, to the appropriate boundary.
const uint32_t header_size = *offset_ptr - Offset;
uint32_t first_tuple_offset = 0; uint32_t first_tuple_offset = 0;
while (first_tuple_offset < header_size) while (first_tuple_offset < header_size)
first_tuple_offset += tuple_size; first_tuple_offset += tuple_size;
// There should be space for at least one tuple.
if (full_length <= first_tuple_offset)
return createStringError(
errc::invalid_argument,
"address range table at offset 0x%" PRIx64
" has an insufficient length to contain any entries",
Offset);
*offset_ptr = Offset + first_tuple_offset; *offset_ptr = Offset + first_tuple_offset;
Descriptor arangeDescriptor; Descriptor arangeDescriptor;
@ -111,14 +154,23 @@ Error DWARFDebugArangeSet::extract(DataExtractor data, uint64_t *offset_ptr) {
"Different datatypes for addresses and sizes!"); "Different datatypes for addresses and sizes!");
assert(sizeof(arangeDescriptor.Address) >= HeaderData.AddrSize); assert(sizeof(arangeDescriptor.Address) >= HeaderData.AddrSize);
while (data.isValidOffset(*offset_ptr)) { uint64_t end_offset = Offset + full_length;
while (*offset_ptr < end_offset) {
arangeDescriptor.Address = data.getUnsigned(offset_ptr, HeaderData.AddrSize); arangeDescriptor.Address = data.getUnsigned(offset_ptr, HeaderData.AddrSize);
arangeDescriptor.Length = data.getUnsigned(offset_ptr, HeaderData.AddrSize); arangeDescriptor.Length = data.getUnsigned(offset_ptr, HeaderData.AddrSize);
// Each set of tuples is terminated by a 0 for the address and 0 if (arangeDescriptor.Length == 0) {
// for the length. // Each set of tuples is terminated by a 0 for the address and 0
if (arangeDescriptor.Address == 0 && arangeDescriptor.Length == 0) // for the length.
return ErrorSuccess(); if (arangeDescriptor.Address == 0 && *offset_ptr == end_offset)
return ErrorSuccess();
return createStringError(
errc::invalid_argument,
"address range table at offset 0x%" PRIx64
" has an invalid tuple (length = 0) at offset 0x%" PRIx64,
Offset, *offset_ptr - tuple_size);
}
ArangeDescriptors.push_back(arangeDescriptor); ArangeDescriptors.push_back(arangeDescriptor);
} }

View File

@ -73,6 +73,23 @@ TEST(DWARFDebugArangeSet, UnsupportedAddressSize) {
"(4 and 8 supported)"); "(4 and 8 supported)");
} }
TEST(DWARFDebugArangeSet, UnsupportedSegmentSelectorSize) {
static const char DebugArangesSecRaw[] =
"\x14\x00\x00\x00" // Length
"\x02\x00" // Version
"\x00\x00\x00\x00" // Debug Info Offset
"\x04" // Address Size
"\x04" // Segment Selector Size (not supported)
// No padding
"\x00\x00\x00\x00" // Termination tuple
"\x00\x00\x00\x00"
"\x00\x00\x00\x00";
ExpectExtractError(
DebugArangesSecRaw,
"non-zero segment selector size in address range table at offset 0x0 "
"is not supported");
}
TEST(DWARFDebugArangeSet, NoTerminationEntry) { TEST(DWARFDebugArangeSet, NoTerminationEntry) {
static const char DebugArangesSecRaw[] = static const char DebugArangesSecRaw[] =
"\x14\x00\x00\x00" // Length "\x14\x00\x00\x00" // Length
@ -90,7 +107,9 @@ TEST(DWARFDebugArangeSet, NoTerminationEntry) {
} }
TEST(DWARFDebugArangeSet, ReservedUnitLength) { TEST(DWARFDebugArangeSet, ReservedUnitLength) {
static const char DebugArangesSecRaw[] = // Note: 12 is the minimum length to pass the basic check for the size of
// the section. 1 will be automatically subtracted in ExpectExtractError().
static const char DebugArangesSecRaw[12 + 1] =
"\xf0\xff\xff\xff"; // Reserved unit length value "\xf0\xff\xff\xff"; // Reserved unit length value
ExpectExtractError( ExpectExtractError(
DebugArangesSecRaw, DebugArangesSecRaw,
@ -98,4 +117,76 @@ TEST(DWARFDebugArangeSet, ReservedUnitLength) {
"of value 0xfffffff0"); "of value 0xfffffff0");
} }
TEST(DWARFDebugArangeSet, SectionTooShort) {
// Note: 1 will be automatically subtracted in ExpectExtractError().
static const char DebugArangesSecRaw[11 + 1] = {0};
ExpectExtractError(
DebugArangesSecRaw,
"section is not large enough to contain an address range table "
"at offset 0x0");
}
TEST(DWARFDebugArangeSet, SectionTooShortDWARF64) {
// Note: 1 will be automatically subtracted in ExpectExtractError().
static const char DebugArangesSecRaw[23 + 1] =
"\xff\xff\xff\xff"; // DWARF64 mark
ExpectExtractError(
DebugArangesSecRaw,
"section is not large enough to contain a DWARF64 address range table "
"at offset 0x0");
}
TEST(DWARFDebugArangeSet, NoSpaceForEntries) {
static const char DebugArangesSecRaw[] =
"\x0c\x00\x00\x00" // Length
"\x02\x00" // Version
"\x00\x00\x00\x00" // Debug Info Offset
"\x04" // Address Size
"\x00" // Segment Selector Size
"\x00\x00\x00\x00" // Padding
; // No entries
ExpectExtractError(
DebugArangesSecRaw,
"address range table at offset 0x0 has an insufficient length "
"to contain any entries");
}
TEST(DWARFDebugArangeSet, UnevenLength) {
static const char DebugArangesSecRaw[] =
"\x1b\x00\x00\x00" // Length (not a multiple of tuple size)
"\x02\x00" // Version
"\x00\x00\x00\x00" // Debug Info Offset
"\x04" // Address Size
"\x00" // Segment Selector Size
"\x00\x00\x00\x00" // Padding
"\x00\x00\x00\x00" // Entry: Address
"\x01\x00\x00\x00" // Length
"\x00\x00\x00\x00" // Termination tuple
"\x00\x00\x00\x00";
ExpectExtractError(
DebugArangesSecRaw,
"address range table at offset 0x0 has length that is not a multiple "
"of the tuple size");
}
TEST(DWARFDebugArangeSet, ZeroLengthEntry) {
static const char DebugArangesSecRaw[] =
"\x24\x00\x00\x00" // Length
"\x02\x00" // Version
"\x00\x00\x00\x00" // Debug Info Offset
"\x04" // Address Size
"\x00" // Segment Selector Size
"\x00\x00\x00\x00" // Padding
"\x00\x00\x00\x00" // Entry1: Address
"\x01\x00\x00\x00" // Length
"\x01\x00\x00\x00" // Entry2: Address
"\x00\x00\x00\x00" // Length (invalid)
"\x00\x00\x00\x00" // Termination tuple
"\x00\x00\x00\x00";
ExpectExtractError(
DebugArangesSecRaw,
"address range table at offset 0x0 has an invalid tuple (length = 0) "
"at offset 0x18");
}
} // end anonymous namespace } // end anonymous namespace