From afc72f154d6c59367e2f1cdf3ead5035748e2b61 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Fri, 23 Aug 2019 10:37:51 +0100 Subject: Prevent a potential illegal memory access in the DWARF parser when processing a corrupt file. PR 24829 * dwarf.c (check_uvalue): New function. Ensures that a block's size is valid. (read_and_display_attr_value): Use check_value when processsing DW_FORM_block attributes. --- binutils/ChangeLog | 8 +++++++ binutils/dwarf.c | 70 +++++++++++++++++++++++++++++++----------------------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 34f2dc0..e5b197a 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,11 @@ +2019-08-23 Nick Clifton + + PR 24829 + * dwarf.c (check_uvalue): New function. Ensures that a block's + size is valid. + (read_and_display_attr_value): Use check_value when processsing + DW_FORM_block attributes. + 2019-08-22 Nick Clifton PR 24921 diff --git a/binutils/dwarf.c b/binutils/dwarf.c index b36406c..2768518 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -1832,6 +1832,34 @@ free_dwo_info (void) first_dwo_info = NULL; } +/* Ensure that START + UVALUE is less than END. + Return an adjusted UVALUE if necessary to ensure this relationship. */ + +static inline dwarf_vma +check_uvalue (const unsigned char * start, + dwarf_vma uvalue, + const unsigned char * end) +{ + dwarf_vma max_uvalue = end - start; + + /* FIXME: Testing "(start + uvalue) < start" miscompiles with gcc 4.8.3 + running on an x86_64 host in 32-bit mode. So we pre-compute the value + here. */ + const unsigned char * ptr = start + uvalue; + + /* See PR 17512: file: 008-103549-0.001:0.1. + and PR 24829 for examples of where these tests are triggered. */ + if (uvalue > max_uvalue + || ptr > end + || ptr < start) + { + warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); + uvalue = max_uvalue; + } + + return uvalue; +} + static unsigned char * read_and_display_attr_value (unsigned long attribute, unsigned long form, @@ -2056,16 +2084,9 @@ read_and_display_attr_value (unsigned long attribute, uvalue = 0; block_start = end; } - /* FIXME: Testing "(block_start + uvalue) < block_start" miscompiles with - gcc 4.8.3 running on an x86_64 host in 32-bit mode. So we pre-compute - block_start + uvalue here. */ - data = block_start + uvalue; - /* PR 17512: file: 008-103549-0.001:0.1. */ - if (block_start + uvalue > end || data < block_start) - { - warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); - uvalue = end - block_start; - } + + uvalue = check_uvalue (block_start, uvalue, end); + if (do_loc) data = block_start + uvalue; else @@ -2081,12 +2102,9 @@ read_and_display_attr_value (unsigned long attribute, uvalue = 0; block_start = end; } - data = block_start + uvalue; - if (block_start + uvalue > end || data < block_start) - { - warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); - uvalue = end - block_start; - } + + uvalue = check_uvalue (block_start, uvalue, end); + if (do_loc) data = block_start + uvalue; else @@ -2102,12 +2120,9 @@ read_and_display_attr_value (unsigned long attribute, uvalue = 0; block_start = end; } - data = block_start + uvalue; - if (block_start + uvalue > end || data < block_start) - { - warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); - uvalue = end - block_start; - } + + uvalue = check_uvalue (block_start, uvalue, end); + if (do_loc) data = block_start + uvalue; else @@ -2124,14 +2139,9 @@ read_and_display_attr_value (unsigned long attribute, uvalue = 0; block_start = end; } - data = block_start + uvalue; - if (block_start + uvalue > end - /* PR 17531: file: 5b5f0592. */ - || data < block_start) - { - warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue); - uvalue = end - block_start; - } + + uvalue = check_uvalue (block_start, uvalue, end); + if (do_loc) data = block_start + uvalue; else -- cgit v1.1