[DebugInfo] Add use of truncating data extractor to debug line parsing

This will ensure that nothing can ever start parsing data from a future
sequence and part-read data will be returned as 0 instead.

Reviewed by: aprantl, labath

Differential Revision: https://reviews.llvm.org/D80796
This commit is contained in:
James Henderson 2020-05-20 15:53:44 +01:00
parent 2b37c5b560
commit e8bcf4ef07
3 changed files with 66 additions and 24 deletions

View File

@ -721,14 +721,17 @@ Error DWARFDebugLine::LineTable::parse(
ProgramLength = BytesRemaining;
}
// Create a DataExtractor which can only see the data up to the end of the
// table, to prevent reading past the end.
const uint64_t EndOffset = DebugLineOffset + ProgramLength;
DWARFDataExtractor TableData(DebugLineData, EndOffset);
// See if we should tell the data extractor the address size.
if (DebugLineData.getAddressSize() == 0)
DebugLineData.setAddressSize(Prologue.getAddressSize());
if (TableData.getAddressSize() == 0)
TableData.setAddressSize(Prologue.getAddressSize());
else
assert(Prologue.getAddressSize() == 0 ||
Prologue.getAddressSize() == DebugLineData.getAddressSize());
Prologue.getAddressSize() == TableData.getAddressSize());
ParsingState State(this, DebugLineOffset, RecoverableErrorHandler);
@ -738,7 +741,7 @@ Error DWARFDebugLine::LineTable::parse(
*OS << format("0x%08.08" PRIx64 ": ", *OffsetPtr);
uint64_t OpcodeOffset = *OffsetPtr;
uint8_t Opcode = DebugLineData.getU8(OffsetPtr);
uint8_t Opcode = TableData.getU8(OffsetPtr);
if (OS)
*OS << format("%02.02" PRIx8 " ", Opcode);
@ -746,7 +749,7 @@ Error DWARFDebugLine::LineTable::parse(
if (Opcode == 0) {
// Extended Opcodes always start with a zero opcode followed by
// a uleb128 length so you can skip ones you don't know about
uint64_t Len = DebugLineData.getULEB128(OffsetPtr);
uint64_t Len = TableData.getULEB128(OffsetPtr);
uint64_t ExtOffset = *OffsetPtr;
// Tolerate zero-length; assume length is correct and soldier on.
@ -756,7 +759,7 @@ Error DWARFDebugLine::LineTable::parse(
continue;
}
uint8_t SubOpcode = DebugLineData.getU8(OffsetPtr);
uint8_t SubOpcode = TableData.getU8(OffsetPtr);
if (OS)
*OS << LNExtendedString(SubOpcode);
switch (SubOpcode) {
@ -789,7 +792,7 @@ Error DWARFDebugLine::LineTable::parse(
// Make sure the extractor knows the address size. If not, infer it
// from the size of the operand.
{
uint8_t ExtractorAddressSize = DebugLineData.getAddressSize();
uint8_t ExtractorAddressSize = TableData.getAddressSize();
uint64_t OpcodeAddressSize = Len - 1;
if (ExtractorAddressSize != OpcodeAddressSize &&
ExtractorAddressSize != 0)
@ -812,13 +815,13 @@ Error DWARFDebugLine::LineTable::parse(
OpcodeAddressSize, ExtOffset));
*OffsetPtr += OpcodeAddressSize;
} else {
DebugLineData.setAddressSize(OpcodeAddressSize);
State.Row.Address.Address = DebugLineData.getRelocatedAddress(
TableData.setAddressSize(OpcodeAddressSize);
State.Row.Address.Address = TableData.getRelocatedAddress(
OffsetPtr, &State.Row.Address.SectionIndex);
// Restore the address size if the extractor already had it.
if (ExtractorAddressSize != 0)
DebugLineData.setAddressSize(ExtractorAddressSize);
TableData.setAddressSize(ExtractorAddressSize);
}
if (OS)
@ -849,12 +852,12 @@ Error DWARFDebugLine::LineTable::parse(
// the file register of the state machine.
{
FileNameEntry FileEntry;
const char *Name = DebugLineData.getCStr(OffsetPtr);
const char *Name = TableData.getCStr(OffsetPtr);
FileEntry.Name =
DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, Name);
FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr);
FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr);
FileEntry.Length = DebugLineData.getULEB128(OffsetPtr);
FileEntry.DirIdx = TableData.getULEB128(OffsetPtr);
FileEntry.ModTime = TableData.getULEB128(OffsetPtr);
FileEntry.Length = TableData.getULEB128(OffsetPtr);
Prologue.FileNames.push_back(FileEntry);
if (OS)
*OS << " (" << Name << ", dir=" << FileEntry.DirIdx << ", mod_time="
@ -864,7 +867,7 @@ Error DWARFDebugLine::LineTable::parse(
break;
case DW_LNE_set_discriminator:
State.Row.Discriminator = DebugLineData.getULEB128(OffsetPtr);
State.Row.Discriminator = TableData.getULEB128(OffsetPtr);
if (OS)
*OS << " (" << State.Row.Discriminator << ")";
break;
@ -913,7 +916,7 @@ Error DWARFDebugLine::LineTable::parse(
// result to the address register of the state machine.
{
uint64_t AddrOffset = State.advanceAddr(
DebugLineData.getULEB128(OffsetPtr), Opcode, OpcodeOffset);
TableData.getULEB128(OffsetPtr), Opcode, OpcodeOffset);
if (OS)
*OS << " (" << AddrOffset << ")";
}
@ -922,7 +925,7 @@ Error DWARFDebugLine::LineTable::parse(
case DW_LNS_advance_line:
// Takes a single signed LEB128 operand and adds that value to
// the line register of the state machine.
State.Row.Line += DebugLineData.getSLEB128(OffsetPtr);
State.Row.Line += TableData.getSLEB128(OffsetPtr);
if (OS)
*OS << " (" << State.Row.Line << ")";
break;
@ -930,7 +933,7 @@ Error DWARFDebugLine::LineTable::parse(
case DW_LNS_set_file:
// Takes a single unsigned LEB128 operand and stores it in the file
// register of the state machine.
State.Row.File = DebugLineData.getULEB128(OffsetPtr);
State.Row.File = TableData.getULEB128(OffsetPtr);
if (OS)
*OS << " (" << State.Row.File << ")";
break;
@ -938,7 +941,7 @@ Error DWARFDebugLine::LineTable::parse(
case DW_LNS_set_column:
// Takes a single unsigned LEB128 operand and stores it in the
// column register of the state machine.
State.Row.Column = DebugLineData.getULEB128(OffsetPtr);
State.Row.Column = TableData.getULEB128(OffsetPtr);
if (OS)
*OS << " (" << State.Row.Column << ")";
break;
@ -986,7 +989,7 @@ Error DWARFDebugLine::LineTable::parse(
// requires the use of DW_LNS_advance_pc. Such assemblers, however,
// can use DW_LNS_fixed_advance_pc instead, sacrificing compression.
{
uint16_t PCOffset = DebugLineData.getRelocatedValue(2, OffsetPtr);
uint16_t PCOffset = TableData.getRelocatedValue(2, OffsetPtr);
State.Row.Address.Address += PCOffset;
if (OS)
*OS
@ -1009,7 +1012,7 @@ Error DWARFDebugLine::LineTable::parse(
case DW_LNS_set_isa:
// Takes a single unsigned LEB128 operand and stores it in the
// column register of the state machine.
State.Row.Isa = DebugLineData.getULEB128(OffsetPtr);
State.Row.Isa = TableData.getULEB128(OffsetPtr);
if (OS)
*OS << " (" << (uint64_t)State.Row.Isa << ")";
break;
@ -1022,7 +1025,7 @@ Error DWARFDebugLine::LineTable::parse(
assert(Opcode - 1U < Prologue.StandardOpcodeLengths.size());
uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1];
for (uint8_t I = 0; I < OpcodeLength; ++I) {
uint64_t Value = DebugLineData.getULEB128(OffsetPtr);
uint64_t Value = TableData.getULEB128(OffsetPtr);
if (OS)
*OS << format("Skipping ULEB128 value: 0x%16.16" PRIx64 ")\n",
Value);

View File

@ -488,6 +488,36 @@
.byte 0, 1, 1 # DW_LNE_end_sequence
.Lunterminated_files_end:
# Opcode extends past the end of the table, as claimed by the unit length field.
.long .Lextended_past_end_end - .Lextended_past_end_start # Length of Unit
.Lextended_past_end_start:
.short 4 # DWARF version number
.long .Lprologue_extended_past_end_end-.Lprologue_extended_past_end_start # Length of Prologue
.Lprologue_extended_past_end_start:
.byte 1 # Minimum Instruction Length
.byte 1 # Maximum Operations per Instruction
.byte 1 # Default is_stmt
.byte -5 # Line Base
.byte 14 # Line Range
.byte 13 # Opcode Base
.byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # Standard Opcode Lengths
.asciz "dir1" # Include table
.asciz "dir2"
.byte 0
.asciz "file1" # File table
.byte 0, 0, 0
.asciz "file2"
.byte 1, 0, 0
.byte 0
.Lprologue_extended_past_end_end:
.byte 0, 9, 2 # DW_LNE_set_address
.quad 0xfeedfeed
.byte 1 # DW_LNS_copy
.byte 0, 9, 2 # DW_LNE_set_address
.long 0xf001f000 # Truncated address (should be 8 bytes)
.byte 0xf0, 0, 1
.Lextended_past_end_end:
# Trailing good section.
.long .Lunit_good_end - .Lunit_good_start # Length of Unit (DWARF-32 format)
.Lunit_good_start:

View File

@ -33,7 +33,7 @@
# RUN: FileCheck %s --input-file=%t-malformed-off-first.err --check-prefix=ALL
## Don't stop looking for the later unit if non-fatal issues are found.
# RUN: llvm-dwarfdump -debug-line=0x3c9 %t-malformed.o 2> %t-malformed-off-last.err \
# RUN: llvm-dwarfdump -debug-line=0x419 %t-malformed.o 2> %t-malformed-off-last.err \
# RUN: | FileCheck %s --check-prefix=LAST --implicit-check-not='debug_line[{{.*}}]'
# RUN: FileCheck %s --input-file=%t-malformed-off-last.err --check-prefix=ALL
@ -243,7 +243,14 @@
# VERBOSE: DW_LNE_set_address (0xababcdcdefef0909)
# VERBOSE-NEXT: DW_LNE_end_sequence
# LAST: debug_line[0x000003c9]
## Table with extended opcode that overruns table end.
# NONFATAL: debug_line[0x000003c9]
# NONFATAL-NEXT: Line table prologue
# VERBOSE: DW_LNE_set_address (0x00000000feedfeed)
# VERBOSE-NEXT: DW_LNS_copy
# VERBOSE: DW_LNE_set_address (0x0000000000000000)
# LAST: debug_line[0x00000419]
# VERBOSE: DW_LNE_set_address (0x00000000cafebabe)
# VERBOSE-NEXT: DW_LNE_end_sequence
@ -272,4 +279,6 @@
# ALL-NEXT: warning: include directories table was not null terminated before the end of the prologue
# ALL-NEXT: warning: parsing line table prologue at 0x00000390 found an invalid directory or file table description at 0x000003bf
# ALL-NEXT: warning: file names table was not null terminated before the end of the prologue
# OTHER-NEXT: warning: unexpected line op length at offset 0x00000411 expected 0x09 found 0x01
# OTHER-NEXT: warning: last sequence in debug line table at offset 0x000003c9 is not terminated
# ALL-NOT: warning: