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.
This commit is contained in:
Alan Modra 2017-04-29 14:48:16 +09:30
parent 45ce1b47e4
commit a941291cab
2 changed files with 27 additions and 12 deletions

View File

@ -1,3 +1,10 @@
2017-04-29 Alan Modra <amodra@gmail.com>
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-28 H.J. Lu <hongjiu.lu@intel.com>
* elf32-i386.c (elf_i386_allocate_dynrelocs): Check plt_got

View File

@ -538,6 +538,22 @@ bfd_check_overflow (enum complain_overflow how,
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
@ -619,15 +635,9 @@ bfd_perform_relocation (bfd *abfd,
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)
/* Check for an overly large offset which
masquerades as a negative value too. */
|| (octets + bfd_get_reloc_size (howto) < bfd_get_reloc_size (howto)))
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
@ -1015,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
@ -1354,8 +1363,7 @@ _bfd_final_link_relocate (reloc_howto_type *howto,
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