From 596245135106b2a965d809e272dc7c758afdc98f Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Wed, 21 Oct 2020 17:42:42 +0100 Subject: [PATCH] Work around problem in DWARF decoding library which can result in attempts to read arbitrary bytes as if they were an LEB128 encoded value. * dwarf.c (skip_attr_bytes): Accept DWARF versions higher than 4 when processing the DW_FORM_ref_addr form. Skip bytes in DW_FORM_block and DW_FORM_exprloc forms. Handle DW_FORM_indirect. (get_type_signedness): Allow a limited amount of recursion. Do not attempt to decode types that use the DW_FORM_ref_addr form. (read_and_display_attr_value): Do not attempt to decode types that use the DW_FORM_ref_addr form. --- binutils/ChangeLog | 11 +++++++++++ binutils/dwarf.c | 43 +++++++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/binutils/ChangeLog b/binutils/ChangeLog index b297de9667c..c560bded833 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,14 @@ +2020-10-21 Nick Clifton + + * dwarf.c (skip_attr_bytes): Accept DWARF versions higher than 4 + when processing the DW_FORM_ref_addr form. + Skip bytes in DW_FORM_block and DW_FORM_exprloc forms. + Handle DW_FORM_indirect. + (get_type_signedness): Allow a limited amount of recursion. + Do not attempt to decode types that use the DW_FORM_ref_addr form. + (read_and_display_attr_value): Do not attempt to decode types + that use the DW_FORM_ref_addr form. + 2020-10-20 Alan Modra * readelf.c: Delete whitespace at end of line throughout. diff --git a/binutils/dwarf.c b/binutils/dwarf.c index e152b20438c..c842aba6c1e 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -1868,7 +1868,7 @@ skip_attr_bytes (unsigned long form, case DW_FORM_ref_addr: if (dwarf_version == 2) SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end); - else if (dwarf_version == 3 || dwarf_version == 4) + else if (dwarf_version > 2) SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end); else return NULL; @@ -1920,6 +1920,7 @@ skip_attr_bytes (unsigned long form, case DW_FORM_ref8: case DW_FORM_data8: + case DW_FORM_ref_sig8: data += 8; break; @@ -1934,6 +1935,7 @@ skip_attr_bytes (unsigned long form, case DW_FORM_block: case DW_FORM_exprloc: READ_ULEB (uvalue, data, end); + data += uvalue; break; case DW_FORM_block1: @@ -1951,12 +1953,12 @@ skip_attr_bytes (unsigned long form, data += 4 + uvalue; break; - case DW_FORM_ref_sig8: - data += 8; - break; - case DW_FORM_indirect: - /* FIXME: Handle this form. */ + READ_ULEB (form, data, end); + if (form == DW_FORM_implicit_const) + SKIP_ULEB (data, end); + return skip_attr_bytes (form, data, end, pointer_size, offset_size, dwarf_version, value_return); + default: return NULL; } @@ -1978,7 +1980,7 @@ get_type_signedness (unsigned char * start, dwarf_vma offset_size, int dwarf_version, bfd_boolean * is_signed, - bfd_boolean is_nested) + unsigned int nesting) { unsigned long abbrev_number; abbrev_entry * entry; @@ -1997,6 +1999,14 @@ get_type_signedness (unsigned char * start, /* FIXME: Issue a warning ? */ return; +#define MAX_NESTING 20 + if (nesting > MAX_NESTING) + { + /* FIXME: Warn - or is this expected ? + NB/ We need to avoid infinite recursion. */ + return; + } + for (attr = entry->first_attr; attr != NULL && attr->attribute; attr = attr->next) @@ -2019,16 +2029,12 @@ get_type_signedness (unsigned char * start, #endif case DW_AT_type: /* Recurse. */ - if (is_nested) - { - /* FIXME: Warn - or is this expected ? - NB/ We need to avoid infinite recursion. */ - return; - } if (uvalue >= (size_t) (end - start)) return; - get_type_signedness (start, start + uvalue, end, pointer_size, - offset_size, dwarf_version, is_signed, TRUE); + /* We cannot correctly process DW_FORM_ref_addr at the moment. */ + if (attr->form != DW_FORM_ref_addr) + get_type_signedness (start, start + uvalue, end, pointer_size, + offset_size, dwarf_version, is_signed, nesting + 1); break; case DW_AT_encoding: @@ -2206,7 +2212,6 @@ read_and_display_attr_value (unsigned long attribute, SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end); else error (_("Internal error: DW_FORM_ref_addr is not supported in DWARF version 1.\n")); - break; case DW_FORM_addr: @@ -2663,8 +2668,10 @@ read_and_display_attr_value (unsigned long attribute, { bfd_boolean is_signed = FALSE; - get_type_signedness (start, start + uvalue, end, pointer_size, - offset_size, dwarf_version, & is_signed, FALSE); + /* We cannot correctly process DW_FORM_ref_addr at the moment. */ + if (form != DW_FORM_ref_addr) + get_type_signedness (start, start + uvalue, end, pointer_size, + offset_size, dwarf_version, & is_signed, 0); level_type_signed[level] = is_signed; } break; -- 2.30.2