Commit b23dc97f authored by Nick Clifton's avatar Nick Clifton
Browse files

Fix a memory access violation when attempting to parse a corrupt COFF binary...

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.
parent 6c6bc899
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)
{
case 0:
{
char x = bfd_get_8 (abfd, addr);
DOIT (x);
bfd_put_8 (abfd, x, addr);
}
break;
if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
reloc_entry->address
* bfd_octets_per_byte (abfd)))
return bfd_reloc_outofrange;
case 1:
{
short x = bfd_get_16 (abfd, addr);
DOIT (x);
bfd_put_16 (abfd, (bfd_vma) x, addr);
}
break;
switch (howto->size)
{
case 0:
{
char x = bfd_get_8 (abfd, addr);
DOIT (x);
bfd_put_8 (abfd, x, addr);
}
break;
case 2:
{
long x = bfd_get_32 (abfd, addr);
DOIT (x);
bfd_put_32 (abfd, (bfd_vma) x, addr);
}
break;
case 1:
{
short x = bfd_get_16 (abfd, addr);
DOIT (x);
bfd_put_16 (abfd, (bfd_vma) x, addr);
}
break;
default:
abort ();
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)
{
......
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment