display_debug_names

* dwarf.c (display_debug_names): Complain when header length is
	too small.  Avoid pointer UB.  Sanity check augmentation string,
	CU table, TU table and foreign TU table sizes.
This commit is contained in:
Alan Modra
2021-05-15 15:29:47 +09:30
parent 5897a38984
commit d7870f6304
2 changed files with 35 additions and 15 deletions

View File

@ -1,3 +1,9 @@
2021-05-15 Alan Modra <amodra@gmail.com>
* dwarf.c (display_debug_names): Complain when header length is
too small. Avoid pointer UB. Sanity check augmentation string,
CU table, TU table and foreign TU table sizes.
2021-05-15 Alan Modra <amodra@gmail.com> 2021-05-15 Alan Modra <amodra@gmail.com>
* dwarf.c (display_debug_frames): Delete initial_length_size. * dwarf.c (display_debug_frames): Delete initial_length_size.

View File

@ -9571,12 +9571,12 @@ display_debug_names (struct dwarf_section *section, void *file)
unsigned int offset_size; unsigned int offset_size;
uint16_t dwarf_version, padding; uint16_t dwarf_version, padding;
uint32_t comp_unit_count, local_type_unit_count, foreign_type_unit_count; uint32_t comp_unit_count, local_type_unit_count, foreign_type_unit_count;
uint32_t bucket_count, name_count, abbrev_table_size; uint64_t bucket_count, name_count, abbrev_table_size;
uint32_t augmentation_string_size; uint32_t augmentation_string_size;
unsigned int i; unsigned int i;
unsigned long sec_off;
bool augmentation_printable; bool augmentation_printable;
const char *augmentation_string; const char *augmentation_string;
size_t total;
unit_start = hdrptr; unit_start = hdrptr;
@ -9591,18 +9591,18 @@ display_debug_names (struct dwarf_section *section, void *file)
} }
else else
offset_size = 4; offset_size = 4;
unit_end = hdrptr + unit_length;
sec_off = hdrptr - section->start; if (unit_length > (size_t) (section_end - hdrptr)
if (sec_off + unit_length < sec_off || unit_length < 2 + 2 + 4 * 7)
|| sec_off + unit_length > section->size)
{ {
too_short:
warn (_("Debug info is corrupted, %s header at %#lx has length %s\n"), warn (_("Debug info is corrupted, %s header at %#lx has length %s\n"),
section->name, section->name,
(unsigned long) (unit_start - section->start), (unsigned long) (unit_start - section->start),
dwarf_vmatoa ("x", unit_length)); dwarf_vmatoa ("x", unit_length));
return 0; return 0;
} }
unit_end = hdrptr + unit_length;
/* Get and check the version number. */ /* Get and check the version number. */
SAFE_BYTE_GET_AND_INC (dwarf_version, hdrptr, 2, unit_end); SAFE_BYTE_GET_AND_INC (dwarf_version, hdrptr, 2, unit_end);
@ -9640,6 +9640,8 @@ display_debug_names (struct dwarf_section *section, void *file)
augmentation_string_size); augmentation_string_size);
augmentation_string_size += (-augmentation_string_size) & 3; augmentation_string_size += (-augmentation_string_size) & 3;
} }
if (augmentation_string_size > (size_t) (unit_end - hdrptr))
goto too_short;
printf (_("Augmentation string:")); printf (_("Augmentation string:"));
@ -9669,6 +9671,9 @@ display_debug_names (struct dwarf_section *section, void *file)
putchar ('\n'); putchar ('\n');
printf (_("CU table:\n")); printf (_("CU table:\n"));
if (_mul_overflow (comp_unit_count, offset_size, &total)
|| total > (size_t) (unit_end - hdrptr))
goto too_short;
for (i = 0; i < comp_unit_count; i++) for (i = 0; i < comp_unit_count; i++)
{ {
uint64_t cu_offset; uint64_t cu_offset;
@ -9679,6 +9684,9 @@ display_debug_names (struct dwarf_section *section, void *file)
putchar ('\n'); putchar ('\n');
printf (_("TU table:\n")); printf (_("TU table:\n"));
if (_mul_overflow (local_type_unit_count, offset_size, &total)
|| total > (size_t) (unit_end - hdrptr))
goto too_short;
for (i = 0; i < local_type_unit_count; i++) for (i = 0; i < local_type_unit_count; i++)
{ {
uint64_t tu_offset; uint64_t tu_offset;
@ -9689,6 +9697,9 @@ display_debug_names (struct dwarf_section *section, void *file)
putchar ('\n'); putchar ('\n');
printf (_("Foreign TU table:\n")); printf (_("Foreign TU table:\n"));
if (_mul_overflow (foreign_type_unit_count, 8, &total)
|| total > (size_t) (unit_end - hdrptr))
goto too_short;
for (i = 0; i < foreign_type_unit_count; i++) for (i = 0; i < foreign_type_unit_count; i++)
{ {
uint64_t signature; uint64_t signature;
@ -9700,6 +9711,18 @@ display_debug_names (struct dwarf_section *section, void *file)
} }
putchar ('\n'); putchar ('\n');
uint64_t xtra = (bucket_count * sizeof (uint32_t)
+ name_count * (sizeof (uint32_t) + 2 * offset_size)
+ abbrev_table_size);
if (xtra > (size_t) (unit_end - hdrptr))
{
warn (_("Entry pool offset (0x%lx) exceeds unit size 0x%lx "
"for unit 0x%lx in the debug_names\n"),
(long) xtra,
(long) (unit_end - unit_start),
(long) (unit_start - section->start));
return 0;
}
const uint32_t *const hash_table_buckets = (uint32_t *) hdrptr; const uint32_t *const hash_table_buckets = (uint32_t *) hdrptr;
hdrptr += bucket_count * sizeof (uint32_t); hdrptr += bucket_count * sizeof (uint32_t);
const uint32_t *const hash_table_hashes = (uint32_t *) hdrptr; const uint32_t *const hash_table_hashes = (uint32_t *) hdrptr;
@ -9712,15 +9735,6 @@ display_debug_names (struct dwarf_section *section, void *file)
hdrptr += abbrev_table_size; hdrptr += abbrev_table_size;
const unsigned char *const abbrev_table_end = hdrptr; const unsigned char *const abbrev_table_end = hdrptr;
unsigned char *const entry_pool = hdrptr; unsigned char *const entry_pool = hdrptr;
if (hdrptr > unit_end)
{
warn (_("Entry pool offset (0x%lx) exceeds unit size 0x%lx "
"for unit 0x%lx in the debug_names\n"),
(long) (hdrptr - section->start),
(long) (unit_end - section->start),
(long) (unit_start - section->start));
return 0;
}
size_t buckets_filled = 0; size_t buckets_filled = 0;
size_t bucketi; size_t bucketi;