From 5ab3907543816d62a8dfd0f7f342ae66814bb0eb Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 12 May 2021 08:51:22 +0930 Subject: [PATCH] PR27849, heap-buffer-overflow on readelf -w PR 27849 * dwarf.c (fetch_indexed_string): Correct length sanity checks. Sanity check section size for version and padding too. Correct index sanity check. Handle multiple tables in .debug_str_offsets. --- binutils/ChangeLog | 7 +++++++ binutils/dwarf.c | 32 ++++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 242563ed3a5..9e0611ea9f4 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,10 @@ +2021-05-12 Alan Modra + + PR 27849 + * dwarf.c (fetch_indexed_string): Correct length sanity checks. + Sanity check section size for version and padding too. Correct + index sanity check. Handle multiple tables in .debug_str_offsets. + 2021-05-11 Hans-Peter Nilsson * dwarf.c (process_abbrev_set): Properly parenthesize before diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 8bc0acb270c..336a3d58392 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -745,7 +745,7 @@ fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set, dwarf_vma str_offset; const char * ret; unsigned char *curr = index_section->start; - const unsigned char *end = curr + index_section->size; + unsigned char *end = curr + index_section->size; dwarf_vma length; if (index_section->start == NULL) @@ -780,16 +780,31 @@ fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set, { /* Skip the version and padding bytes. We assume that they are correct. */ - curr += 4; + if (end - curr >= 4) + curr += 4; + else + curr = end; + if (length >= 4) + length -= 4; + else + length = 0; + + if (this_set != NULL + && this_set->section_sizes[DW_SECT_STR_OFFSETS] < length) + length = this_set->section_sizes[DW_SECT_STR_OFFSETS]; - /* FIXME: The code below assumes that there is only one table - in the .debug_str_offsets section, so check that now. */ - if ((offset_size == 4 && curr + length < (end - 8)) - || (offset_size == 8 && curr + length < (end - 16))) + if (length > (dwarf_vma) (end - curr)) { - warn (_("index table size is too small %s vs %s\n"), + warn (_("index table size too large for section %s vs %s\n"), dwarf_vmatoa ("x", length), dwarf_vmatoa ("x", index_section->size)); + length = end - curr; + } + + if (length < offset_size) + { + warn (_("index table size %s is too small\n"), + dwarf_vmatoa ("x", length)); return _(""); } } @@ -799,7 +814,8 @@ fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set, if (this_set != NULL) index_offset += this_set->section_offsets [DW_SECT_STR_OFFSETS]; - if (index_offset >= length) + if (index_offset >= length + || length - index_offset < offset_size) { warn (_("DW_FORM_GNU_str_index offset too big: 0x%s vs 0x%s\n"), dwarf_vmatoa ("x", index_offset), -- 2.30.2