From a941291cab71b9ac356e1c03968c177c03e602ab Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Sat, 29 Apr 2017 14:48:16 +0930 Subject: [PATCH] PR21432, buffer overflow in perform_relocation The existing reloc offset range tests didn't catch small negative offsets less than the size of the reloc field. PR 21432 * reloc.c (reloc_offset_in_range): New function. (bfd_perform_relocation, bfd_install_relocation): Use it. (_bfd_final_link_relocate): Likewise. Upstream-Status: Backport CVE: CVE-2017-8396 CVE: CVE-2017-8397 Signed-off-by: Armin Kuster --- bfd/ChangeLog | 7 +++++++ bfd/reloc.c | 32 ++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 12 deletions(-) Index: git/bfd/reloc.c =================================================================== --- git.orig/bfd/reloc.c +++ git/bfd/reloc.c @@ -538,6 +538,22 @@ bfd_check_overflow (enum complain_overfl return flag; } +/* HOWTO describes a relocation, at offset OCTET. Return whether the + relocation field is within SECTION of ABFD. */ + +static bfd_boolean +reloc_offset_in_range (reloc_howto_type *howto, bfd *abfd, + asection *section, bfd_size_type octet) +{ + bfd_size_type octet_end = bfd_get_section_limit_octets (abfd, section); + bfd_size_type reloc_size = bfd_get_reloc_size (howto); + + /* The reloc field must be contained entirely within the section. + Allow zero length fields (marker relocs or NONE relocs where no + relocation will be performed) at the end of the section. */ + return octet <= octet_end && octet + reloc_size <= octet_end; +} + /* FUNCTION bfd_perform_relocation @@ -618,13 +634,10 @@ bfd_perform_relocation (bfd *abfd, /* PR 17512: file: 0f67f69d. */ if (howto == NULL) return bfd_reloc_undefined; - - /* Is the address of the relocation really within the section? - Include the size of the reloc in the test for out of range addresses. - PR 17512: file: c146ab8b, 46dff27f, 38e53ebf. */ + + /* Is the address of the relocation really within the section? */ octets = reloc_entry->address * bfd_octets_per_byte (abfd); - if (octets + bfd_get_reloc_size (howto) - > bfd_get_section_limit_octets (abfd, input_section)) + if (!reloc_offset_in_range (howto, abfd, input_section, octets)) return bfd_reloc_outofrange; /* Work out which section the relocation is targeted at and the @@ -1012,8 +1025,7 @@ bfd_install_relocation (bfd *abfd, /* Is the address of the relocation really within the section? */ octets = reloc_entry->address * bfd_octets_per_byte (abfd); - if (octets + bfd_get_reloc_size (howto) - > bfd_get_section_limit_octets (abfd, input_section)) + if (!reloc_offset_in_range (howto, abfd, input_section, octets)) return bfd_reloc_outofrange; /* Work out which section the relocation is targeted at and the @@ -1351,8 +1363,7 @@ _bfd_final_link_relocate (reloc_howto_ty bfd_size_type octets = address * bfd_octets_per_byte (input_bfd); /* Sanity check the address. */ - if (octets + bfd_get_reloc_size (howto) - > bfd_get_section_limit_octets (input_bfd, input_section)) + if (!reloc_offset_in_range (howto, input_bfd, input_section, octets)) return bfd_reloc_outofrange; /* This function assumes that we are dealing with a basic relocation Index: git/bfd/ChangeLog =================================================================== --- git.orig/bfd/ChangeLog +++ git/bfd/ChangeLog @@ -1,3 +1,10 @@ +2017-04-29 Alan Modra + + PR 21432 + * reloc.c (reloc_offset_in_range): New function. + (bfd_perform_relocation, bfd_install_relocation): Use it. + (_bfd_final_link_relocate): Likewise. + 2017-04-26 Nick Clifton PR binutils/21431