Fix a memory access violation when attempting to parse a corrupt COFF binary with a relocation that points beyond the end of the section to be relocated.
PR 22506 * reloc.c (reloc_offset_in_range): Rename to bfd_reloc_offset_in_range and export. (bfd_perform_relocation): Rename function invocation. (bfd_install_relocation): Likewise. (bfd_final_link_relocate): Likewise. * bfd-in2.h: Regenerate. * coff-arm.c (coff_arm_reloc): Use bfd_reloc_offset_in_range. * coff-i386.c (coff_i386_reloc): Likewise. * coff-i860.c (coff_i860_reloc): Likewise. * coff-m68k.c (mk68kcoff_common_addend_special_fn): Likewise. * coff-m88k.c (m88k_special_reloc): Likewise. * coff-mips.c (mips_reflo_reloc): Likewise. * coff-x86_64.c (coff_amd64_reloc): Likewise.
This commit is contained in:
parent
6c6bc89930
commit
b23dc97fe2
|
@ -1,3 +1,20 @@
|
|||
2017-11-28 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
PR 22506
|
||||
* reloc.c (reloc_offset_in_range): Rename to
|
||||
bfd_reloc_offset_in_range and export.
|
||||
(bfd_perform_relocation): Rename function invocation.
|
||||
(bfd_install_relocation): Likewise.
|
||||
(bfd_final_link_relocate): Likewise.
|
||||
* bfd-in2.h: Regenerate.
|
||||
* coff-arm.c (coff_arm_reloc): Use bfd_reloc_offset_in_range.
|
||||
* coff-i386.c (coff_i386_reloc): Likewise.
|
||||
* coff-i860.c (coff_i860_reloc): Likewise.
|
||||
* coff-m68k.c (mk68kcoff_common_addend_special_fn): Likewise.
|
||||
* coff-m88k.c (m88k_special_reloc): Likewise.
|
||||
* coff-mips.c (mips_reflo_reloc): Likewise.
|
||||
* coff-x86_64.c (coff_amd64_reloc): Likewise.
|
||||
|
||||
2017-11-28 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
* elf-m10300.c (mn10300_elf_check_relocs): Don't set
|
||||
|
|
|
@ -2662,6 +2662,12 @@ bfd_reloc_status_type bfd_check_overflow
|
|||
unsigned int addrsize,
|
||||
bfd_vma relocation);
|
||||
|
||||
bfd_boolean bfd_reloc_offset_in_range
|
||||
(reloc_howto_type *howto,
|
||||
bfd *abfd,
|
||||
asection *section,
|
||||
bfd_size_type offset);
|
||||
|
||||
bfd_reloc_status_type bfd_perform_relocation
|
||||
(bfd *abfd,
|
||||
arelent *reloc_entry,
|
||||
|
|
|
@ -109,41 +109,46 @@ coff_arm_reloc (bfd *abfd,
|
|||
x = ((x & ~howto->dst_mask) \
|
||||
| (((x & howto->src_mask) + diff) & howto->dst_mask))
|
||||
|
||||
if (diff != 0)
|
||||
{
|
||||
reloc_howto_type *howto = reloc_entry->howto;
|
||||
unsigned char *addr = (unsigned char *) data + reloc_entry->address;
|
||||
if (diff != 0)
|
||||
{
|
||||
reloc_howto_type *howto = reloc_entry->howto;
|
||||
unsigned char *addr = (unsigned char *) data + reloc_entry->address;
|
||||
|
||||
switch (howto->size)
|
||||
if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
|
||||
reloc_entry->address
|
||||
* bfd_octets_per_byte (abfd)))
|
||||
return bfd_reloc_outofrange;
|
||||
|
||||
switch (howto->size)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
char x = bfd_get_8 (abfd, addr);
|
||||
DOIT (x);
|
||||
bfd_put_8 (abfd, x, addr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
short x = bfd_get_16 (abfd, addr);
|
||||
DOIT (x);
|
||||
bfd_put_16 (abfd, (bfd_vma) x, addr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
long x = bfd_get_32 (abfd, addr);
|
||||
DOIT (x);
|
||||
bfd_put_32 (abfd, (bfd_vma) x, addr);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
char x = bfd_get_8 (abfd, addr);
|
||||
DOIT (x);
|
||||
bfd_put_8 (abfd, x, addr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
short x = bfd_get_16 (abfd, addr);
|
||||
DOIT (x);
|
||||
bfd_put_16 (abfd, (bfd_vma) x, addr);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
long x = bfd_get_32 (abfd, addr);
|
||||
DOIT (x);
|
||||
bfd_put_32 (abfd, (bfd_vma) x, addr);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Now let bfd_perform_relocation finish everything up. */
|
||||
return bfd_reloc_continue;
|
||||
|
|
|
@ -144,6 +144,11 @@ coff_i386_reloc (bfd *abfd,
|
|||
reloc_howto_type *howto = reloc_entry->howto;
|
||||
unsigned char *addr = (unsigned char *) data + reloc_entry->address;
|
||||
|
||||
if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
|
||||
reloc_entry->address
|
||||
* bfd_octets_per_byte (abfd)))
|
||||
return bfd_reloc_outofrange;
|
||||
|
||||
switch (howto->size)
|
||||
{
|
||||
case 0:
|
||||
|
|
|
@ -95,6 +95,11 @@ coff_i860_reloc (bfd *abfd,
|
|||
reloc_howto_type *howto = reloc_entry->howto;
|
||||
unsigned char *addr = (unsigned char *) data + reloc_entry->address;
|
||||
|
||||
if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
|
||||
reloc_entry->address
|
||||
* bfd_octets_per_byte (abfd)))
|
||||
return bfd_reloc_outofrange;
|
||||
|
||||
switch (howto->size)
|
||||
{
|
||||
case 0:
|
||||
|
|
|
@ -305,6 +305,11 @@ m68kcoff_common_addend_special_fn (bfd *abfd,
|
|||
reloc_howto_type *howto = reloc_entry->howto;
|
||||
unsigned char *addr = (unsigned char *) data + reloc_entry->address;
|
||||
|
||||
if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
|
||||
reloc_entry->address
|
||||
* bfd_octets_per_byte (abfd)))
|
||||
return bfd_reloc_outofrange;
|
||||
|
||||
switch (howto->size)
|
||||
{
|
||||
case 0:
|
||||
|
|
|
@ -72,10 +72,17 @@ m88k_special_reloc (bfd *abfd,
|
|||
{
|
||||
bfd_vma output_base = 0;
|
||||
bfd_vma addr = reloc_entry->address;
|
||||
bfd_vma x = bfd_get_16 (abfd, (bfd_byte *) data + addr);
|
||||
bfd_vma x;
|
||||
asection *reloc_target_output_section;
|
||||
long relocation = 0;
|
||||
|
||||
if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
|
||||
reloc_entry->address
|
||||
* bfd_octets_per_byte (abfd)))
|
||||
return bfd_reloc_outofrange;
|
||||
|
||||
x = bfd_get_16 (abfd, (bfd_byte *) data + addr);
|
||||
|
||||
/* Work out which section the relocation is targeted at and the
|
||||
initial relocation command value. */
|
||||
|
||||
|
|
|
@ -504,6 +504,12 @@ mips_reflo_reloc (bfd *abfd ATTRIBUTE_UNUSED,
|
|||
unsigned long vallo;
|
||||
struct mips_hi *next;
|
||||
|
||||
if (! bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
|
||||
input_section,
|
||||
reloc_entry->address
|
||||
* bfd_octets_per_byte (abfd)))
|
||||
return bfd_reloc_outofrange;
|
||||
|
||||
/* Do the REFHI relocation. Note that we actually don't
|
||||
need to know anything about the REFLO itself, except
|
||||
where to find the low 16 bits of the addend needed by the
|
||||
|
|
|
@ -142,17 +142,11 @@ coff_amd64_reloc (bfd *abfd,
|
|||
{
|
||||
reloc_howto_type *howto = reloc_entry->howto;
|
||||
unsigned char *addr = (unsigned char *) data + reloc_entry->address;
|
||||
|
||||
/* FIXME: We do not have an end address for data, so we cannot
|
||||
accurately range check any addresses computed against it.
|
||||
cf: PR binutils/17512: file: 1085-1761-0.004.
|
||||
For now we do the best that we can. */
|
||||
if (addr < (unsigned char *) data
|
||||
|| addr > ((unsigned char *) data) + input_section->size)
|
||||
{
|
||||
bfd_set_error (bfd_error_bad_value);
|
||||
return bfd_reloc_notsupported;
|
||||
}
|
||||
|
||||
if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
|
||||
reloc_entry->address
|
||||
* bfd_octets_per_byte (abfd)))
|
||||
return bfd_reloc_outofrange;
|
||||
|
||||
switch (howto->size)
|
||||
{
|
||||
|
|
40
bfd/reloc.c
40
bfd/reloc.c
|
@ -540,12 +540,31 @@ bfd_check_overflow (enum complain_overflow how,
|
|||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
FUNCTION
|
||||
bfd_reloc_offset_in_range
|
||||
|
||||
SYNOPSIS
|
||||
bfd_boolean bfd_reloc_offset_in_range
|
||||
(reloc_howto_type *howto,
|
||||
bfd *abfd,
|
||||
asection *section,
|
||||
bfd_size_type offset);
|
||||
|
||||
DESCRIPTION
|
||||
Returns TRUE if the reloc described by @var{HOWTO} can be
|
||||
applied at @var{OFFSET} octets in @var{SECTION}.
|
||||
|
||||
*/
|
||||
|
||||
/* 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_boolean
|
||||
bfd_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);
|
||||
|
@ -619,6 +638,11 @@ bfd_perform_relocation (bfd *abfd,
|
|||
if (howto && howto->special_function)
|
||||
{
|
||||
bfd_reloc_status_type cont;
|
||||
|
||||
/* Note - we do not call bfd_reloc_offset_in_range here as the
|
||||
reloc_entry->address field might actually be valid for the
|
||||
backend concerned. It is up to the special_function itself
|
||||
to call bfd_reloc_offset_in_range if needed. */
|
||||
cont = howto->special_function (abfd, reloc_entry, symbol, data,
|
||||
input_section, output_bfd,
|
||||
error_message);
|
||||
|
@ -639,7 +663,7 @@ bfd_perform_relocation (bfd *abfd,
|
|||
|
||||
/* Is the address of the relocation really within the section? */
|
||||
octets = reloc_entry->address * bfd_octets_per_byte (abfd);
|
||||
if (!reloc_offset_in_range (howto, abfd, input_section, octets))
|
||||
if (!bfd_reloc_offset_in_range (howto, abfd, input_section, octets))
|
||||
return bfd_reloc_outofrange;
|
||||
|
||||
/* Work out which section the relocation is targeted at and the
|
||||
|
@ -1005,6 +1029,10 @@ bfd_install_relocation (bfd *abfd,
|
|||
{
|
||||
bfd_reloc_status_type cont;
|
||||
|
||||
/* Note - we do not call bfd_reloc_offset_in_range here as the
|
||||
reloc_entry->address field might actually be valid for the
|
||||
backend concerned. It is up to the special_function itself
|
||||
to call bfd_reloc_offset_in_range if needed. */
|
||||
/* XXX - The special_function calls haven't been fixed up to deal
|
||||
with creating new relocations and section contents. */
|
||||
cont = howto->special_function (abfd, reloc_entry, symbol,
|
||||
|
@ -1027,7 +1055,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 (!reloc_offset_in_range (howto, abfd, input_section, octets))
|
||||
if (!bfd_reloc_offset_in_range (howto, abfd, input_section, octets))
|
||||
return bfd_reloc_outofrange;
|
||||
|
||||
/* Work out which section the relocation is targeted at and the
|
||||
|
@ -1365,7 +1393,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 (!reloc_offset_in_range (howto, input_bfd, input_section, octets))
|
||||
if (!bfd_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
|
||||
|
|
Loading…
Reference in New Issue