mirror of
https://git.yoctoproject.org/poky
synced 2026-03-31 20:02:22 +02:00
Affects: <= 2.29.1 (From OE-Core rev: 942e7f65fd656f2cc526a3c99edcea60f341132c) Signed-off-by: Armin Kuster <akuster@mvista.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
367 lines
12 KiB
Diff
367 lines
12 KiB
Diff
From b23dc97fe237a1d9e850d7cbeee066183a00630b Mon Sep 17 00:00:00 2001
|
|
From: Nick Clifton <nickc@redhat.com>
|
|
Date: Tue, 28 Nov 2017 13:20:31 +0000
|
|
Subject: [PATCH] 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.
|
|
|
|
Upstream-Status: Backport
|
|
Affects: <= 2.29.1
|
|
CVE: CVE-2017-17121
|
|
Signed-off-by: Armin Kuster <akuster@mvista.com>
|
|
|
|
---
|
|
bfd/ChangeLog | 17 +++++++++++++++
|
|
bfd/bfd-in2.h | 6 +++++
|
|
bfd/coff-arm.c | 65 ++++++++++++++++++++++++++++++-------------------------
|
|
bfd/coff-i386.c | 5 +++++
|
|
bfd/coff-i860.c | 5 +++++
|
|
bfd/coff-m68k.c | 5 +++++
|
|
bfd/coff-m88k.c | 9 +++++++-
|
|
bfd/coff-mips.c | 6 +++++
|
|
bfd/coff-x86_64.c | 16 +++++---------
|
|
bfd/reloc.c | 40 +++++++++++++++++++++++++++++-----
|
|
10 files changed, 126 insertions(+), 48 deletions(-)
|
|
|
|
Index: git/bfd/bfd-in2.h
|
|
===================================================================
|
|
--- git.orig/bfd/bfd-in2.h
|
|
+++ git/bfd/bfd-in2.h
|
|
@@ -2661,6 +2661,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,
|
|
Index: git/bfd/coff-arm.c
|
|
===================================================================
|
|
--- git.orig/bfd/coff-arm.c
|
|
+++ git/bfd/coff-arm.c
|
|
@@ -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;
|
|
+
|
|
+ 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:
|
|
+ {
|
|
+ char x = bfd_get_8 (abfd, addr);
|
|
+ DOIT (x);
|
|
+ bfd_put_8 (abfd, x, addr);
|
|
+ }
|
|
+ break;
|
|
|
|
- switch (howto->size)
|
|
+ case 1:
|
|
{
|
|
- 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;
|
|
+ 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;
|
|
Index: git/bfd/coff-i386.c
|
|
===================================================================
|
|
--- git.orig/bfd/coff-i386.c
|
|
+++ git/bfd/coff-i386.c
|
|
@@ -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:
|
|
Index: git/bfd/coff-i860.c
|
|
===================================================================
|
|
--- git.orig/bfd/coff-i860.c
|
|
+++ git/bfd/coff-i860.c
|
|
@@ -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:
|
|
Index: git/bfd/coff-m68k.c
|
|
===================================================================
|
|
--- git.orig/bfd/coff-m68k.c
|
|
+++ git/bfd/coff-m68k.c
|
|
@@ -305,6 +305,11 @@ m68kcoff_common_addend_special_fn (bfd *
|
|
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:
|
|
Index: git/bfd/coff-m88k.c
|
|
===================================================================
|
|
--- git.orig/bfd/coff-m88k.c
|
|
+++ git/bfd/coff-m88k.c
|
|
@@ -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. */
|
|
|
|
Index: git/bfd/coff-mips.c
|
|
===================================================================
|
|
--- git.orig/bfd/coff-mips.c
|
|
+++ git/bfd/coff-mips.c
|
|
@@ -504,6 +504,12 @@ mips_reflo_reloc (bfd *abfd ATTRIBUTE_UN
|
|
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
|
|
Index: git/bfd/coff-x86_64.c
|
|
===================================================================
|
|
--- git.orig/bfd/coff-x86_64.c
|
|
+++ git/bfd/coff-x86_64.c
|
|
@@ -143,16 +143,10 @@ 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)
|
|
{
|
|
Index: git/bfd/reloc.c
|
|
===================================================================
|
|
--- git.orig/bfd/reloc.c
|
|
+++ git/bfd/reloc.c
|
|
@@ -538,12 +538,31 @@ bfd_check_overflow (enum complain_overfl
|
|
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);
|
|
@@ -617,6 +636,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);
|
|
@@ -637,7 +661,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
|
|
@@ -1003,6 +1027,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,
|
|
@@ -1025,7 +1053,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
|
|
@@ -1363,7 +1391,7 @@ _bfd_final_link_relocate (reloc_howto_ty
|
|
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
|
|
Index: git/bfd/ChangeLog
|
|
===================================================================
|
|
--- git.orig/bfd/ChangeLog
|
|
+++ git/bfd/ChangeLog
|
|
@@ -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-16 Nick Clifton <nickc@redhat.com>
|
|
|
|
PR 22421
|