summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2017-09-04 16:31:12 +0100
committerNick Clifton <nickc@redhat.com>2017-09-04 16:31:12 +0100
commitdeeb3d27c254ad8bf8c3877fa6b61817f56191f5 (patch)
treeac94a290657a92c24c3ccff49613dd42ad3aa649
parenta541116faa5716d5c1a4bc9d1567855902b89a87 (diff)
downloadbinutils-gdb-deeb3d27c254ad8bf8c3877fa6b61817f56191f5.tar.gz
Import patch from mainline to fix address violation errors when parsing corrupt VMS and MACHO binaries.
PR 21813 * mach-o.c (bfd_mach_o_canonicalize_relocs): Pass the base address of the relocs to the canonicalize_one_reloc routine. * mach-o.h (struct bfd_mach_o_backend_data): Update the prototype for the _bfd_mach_o_canonicalize_one_reloc field. * mach-o-arm.c (bfd_mach_o_arm_canonicalize_one_reloc): Add res_base parameter. Use to check for corrupt pair relocs. * mach-o-aarch64.c (bfd_mach_o_arm64_canonicalize_one_reloc): Likewise. * mach-o-i386.c (bfd_mach_o_i386_canonicalize_one_reloc): Likewise. * mach-o-x86-64.c (bfd_mach_o_x86_64_canonicalize_one_reloc): Likewise. * vms-alpha.c (_bfd_vms_slurp_eihd): Make sure that there is enough data in the record before attempting to parse it. (_bfd_vms_slurp_eeom): Likewise. (_bfd_vms_slurp_egsd): Check for an invalid section index. (image_set_ptr): Likewise. (alpha_vms_slurp_relocs): Likewise. (alpha_vms_object_p): Check for a truncated record.
-rw-r--r--bfd/ChangeLog21
-rw-r--r--bfd/mach-o-aarch64.c6
-rw-r--r--bfd/mach-o-arm.c9
-rw-r--r--bfd/mach-o-i386.c7
-rw-r--r--bfd/mach-o-x86-64.c6
-rw-r--r--bfd/mach-o.c2
-rw-r--r--bfd/mach-o.h2
-rw-r--r--bfd/vms-alpha.c62
8 files changed, 101 insertions, 14 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 7be3d8267a7..ac1e404081d 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -26,6 +26,27 @@
correct magic bytes at the start, set the error to wrong format
and clear the format selector before returning NULL.
+ PR 21813
+ * mach-o.c (bfd_mach_o_canonicalize_relocs): Pass the base address
+ of the relocs to the canonicalize_one_reloc routine.
+ * mach-o.h (struct bfd_mach_o_backend_data): Update the prototype
+ for the _bfd_mach_o_canonicalize_one_reloc field.
+ * mach-o-arm.c (bfd_mach_o_arm_canonicalize_one_reloc): Add
+ res_base parameter. Use to check for corrupt pair relocs.
+ * mach-o-aarch64.c (bfd_mach_o_arm64_canonicalize_one_reloc):
+ Likewise.
+ * mach-o-i386.c (bfd_mach_o_i386_canonicalize_one_reloc):
+ Likewise.
+ * mach-o-x86-64.c (bfd_mach_o_x86_64_canonicalize_one_reloc):
+ Likewise.
+ * vms-alpha.c (_bfd_vms_slurp_eihd): Make sure that there is
+ enough data in the record before attempting to parse it.
+ (_bfd_vms_slurp_eeom): Likewise.
+ (_bfd_vms_slurp_egsd): Check for an invalid section index.
+ (image_set_ptr): Likewise.
+ (alpha_vms_slurp_relocs): Likewise.
+ (alpha_vms_object_p): Check for a truncated record.
+
2017-09-04 Alan Modra <amodra@gmail.com>
PR 22067
diff --git a/bfd/mach-o-aarch64.c b/bfd/mach-o-aarch64.c
index 12fc47eb0a3..8fc6831a394 100644
--- a/bfd/mach-o-aarch64.c
+++ b/bfd/mach-o-aarch64.c
@@ -148,8 +148,10 @@ static reloc_howto_type arm64_howto_table[]=
static bfd_boolean
bfd_mach_o_arm64_canonicalize_one_reloc (bfd *abfd,
- struct mach_o_reloc_info_external *raw,
- arelent *res, asymbol **syms)
+ struct mach_o_reloc_info_external *raw,
+ arelent *res,
+ asymbol **syms,
+ arelent *res_base ATTRIBUTE_UNUSED)
{
bfd_mach_o_reloc_info reloc;
diff --git a/bfd/mach-o-arm.c b/bfd/mach-o-arm.c
index da58679761f..daeae70ce76 100644
--- a/bfd/mach-o-arm.c
+++ b/bfd/mach-o-arm.c
@@ -148,8 +148,10 @@ static reloc_howto_type arm_howto_table[]=
static bfd_boolean
bfd_mach_o_arm_canonicalize_one_reloc (bfd *abfd,
- struct mach_o_reloc_info_external *raw,
- arelent *res, asymbol **syms)
+ struct mach_o_reloc_info_external *raw,
+ arelent *res,
+ asymbol **syms,
+ arelent *res_base)
{
bfd_mach_o_reloc_info reloc;
@@ -161,6 +163,9 @@ bfd_mach_o_arm_canonicalize_one_reloc (bfd *abfd,
switch (reloc.r_type)
{
case BFD_MACH_O_ARM_RELOC_PAIR:
+ /* PR 21813: Check for a corrupt PAIR reloc at the start. */
+ if (res == res_base)
+ return FALSE;
if (reloc.r_length == 2)
{
res->howto = &arm_howto_table[7];
diff --git a/bfd/mach-o-i386.c b/bfd/mach-o-i386.c
index 82a711e661b..a2f8380913a 100644
--- a/bfd/mach-o-i386.c
+++ b/bfd/mach-o-i386.c
@@ -114,7 +114,9 @@ static reloc_howto_type i386_howto_table[]=
static bfd_boolean
bfd_mach_o_i386_canonicalize_one_reloc (bfd *abfd,
struct mach_o_reloc_info_external *raw,
- arelent *res, asymbol **syms)
+ arelent *res,
+ asymbol **syms,
+ arelent *res_base)
{
bfd_mach_o_reloc_info reloc;
@@ -126,6 +128,9 @@ bfd_mach_o_i386_canonicalize_one_reloc (bfd *abfd,
switch (reloc.r_type)
{
case BFD_MACH_O_GENERIC_RELOC_PAIR:
+ /* PR 21813: Check for a corrupt PAIR reloc at the start. */
+ if (res == res_base)
+ return FALSE;
if (reloc.r_length == 2)
{
res->howto = &i386_howto_table[7];
diff --git a/bfd/mach-o-x86-64.c b/bfd/mach-o-x86-64.c
index 1c83b1083db..a374550d335 100644
--- a/bfd/mach-o-x86-64.c
+++ b/bfd/mach-o-x86-64.c
@@ -121,8 +121,10 @@ static reloc_howto_type x86_64_howto_table[]=
static bfd_boolean
bfd_mach_o_x86_64_canonicalize_one_reloc (bfd *abfd,
- struct mach_o_reloc_info_external *raw,
- arelent *res, asymbol **syms)
+ struct mach_o_reloc_info_external *raw,
+ arelent *res,
+ asymbol **syms,
+ arelent *res_base ATTRIBUTE_UNUSED)
{
bfd_mach_o_reloc_info reloc;
diff --git a/bfd/mach-o.c b/bfd/mach-o.c
index 51920df6833..3190774b439 100644
--- a/bfd/mach-o.c
+++ b/bfd/mach-o.c
@@ -1496,7 +1496,7 @@ bfd_mach_o_canonicalize_relocs (bfd *abfd, unsigned long filepos,
for (i = 0; i < count; i++)
{
if (!(*bed->_bfd_mach_o_canonicalize_one_reloc)(abfd, &native_relocs[i],
- &res[i], syms))
+ &res[i], syms, res))
goto err;
}
free (native_relocs);
diff --git a/bfd/mach-o.h b/bfd/mach-o.h
index 83660a4ce9a..0719b53b1e0 100644
--- a/bfd/mach-o.h
+++ b/bfd/mach-o.h
@@ -746,7 +746,7 @@ typedef struct bfd_mach_o_backend_data
enum bfd_architecture arch;
bfd_vma page_size;
bfd_boolean (*_bfd_mach_o_canonicalize_one_reloc)
- (bfd *, struct mach_o_reloc_info_external *, arelent *, asymbol **);
+ (bfd *, struct mach_o_reloc_info_external *, arelent *, asymbol **, arelent *);
bfd_boolean (*_bfd_mach_o_swap_reloc_out)(arelent *, bfd_mach_o_reloc_info *);
bfd_boolean (*_bfd_mach_o_print_thread)(bfd *, bfd_mach_o_thread_flavour *,
void *, char *);
diff --git a/bfd/vms-alpha.c b/bfd/vms-alpha.c
index 0b41db4409e..d8ffa4ea658 100644
--- a/bfd/vms-alpha.c
+++ b/bfd/vms-alpha.c
@@ -473,6 +473,14 @@ _bfd_vms_slurp_eihd (bfd *abfd, unsigned int *eisd_offset,
vms_debug2 ((8, "_bfd_vms_slurp_eihd\n"));
+ /* PR 21813: Check for an undersized record. */
+ if (PRIV (recrd.buf_size) < sizeof (* eihd))
+ {
+ _bfd_error_handler (_("Corrupt EIHD record - size is too small"));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
size = bfd_getl32 (eihd->size);
imgtype = bfd_getl32 (eihd->imgtype);
@@ -1312,19 +1320,38 @@ _bfd_vms_slurp_egsd (bfd *abfd)
if (old_flags & EGSY__V_DEF)
{
struct vms_esdf *esdf = (struct vms_esdf *)vms_rec;
+ long psindx;
entry->value = bfd_getl64 (esdf->value);
if (PRIV (sections) == NULL)
return FALSE;
- entry->section = PRIV (sections)[bfd_getl32 (esdf->psindx)];
+
+ psindx = bfd_getl32 (esdf->psindx);
+ /* PR 21813: Check for an out of range index. */
+ if (psindx < 0 || psindx >= (int) PRIV (section_count))
+ {
+ _bfd_error_handler (_("Corrupt EGSD record: its psindx field is too big (%#lx)"),
+ psindx);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ entry->section = PRIV (sections)[psindx];
if (old_flags & EGSY__V_NORM)
{
PRIV (norm_sym_count)++;
entry->code_value = bfd_getl64 (esdf->code_address);
- entry->code_section =
- PRIV (sections)[bfd_getl32 (esdf->ca_psindx)];
+ psindx = bfd_getl32 (esdf->ca_psindx);
+ /* PR 21813: Check for an out of range index. */
+ if (psindx < 0 || psindx >= (int) PRIV (section_count))
+ {
+ _bfd_error_handler (_("Corrupt EGSD record: its psindx field is too big (%#lx)"),
+ psindx);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ entry->code_section = PRIV (sections)[psindx];
}
}
}
@@ -1351,9 +1378,20 @@ _bfd_vms_slurp_egsd (bfd *abfd)
if (old_flags & EGSY__V_REL)
{
+ long psindx;
+
if (PRIV (sections) == NULL)
return FALSE;
- entry->section = PRIV (sections)[bfd_getl32 (egst->psindx)];
+ psindx = bfd_getl32 (egst->psindx);
+ /* PR 21813: Check for an out of range index. */
+ if (psindx < 0 || psindx >= (int) PRIV (section_count))
+ {
+ _bfd_error_handler (_("Corrupt EGSD record: its psindx field is too big (%#lx)"),
+ psindx);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ entry->section = PRIV (sections)[psindx];
}
else
entry->section = bfd_abs_section_ptr;
@@ -1446,6 +1484,9 @@ image_set_ptr (bfd *abfd, bfd_vma vma, int sect, struct bfd_link_info *info)
if (PRIV (sections) == NULL)
return;
+ if (sect < 0 || sect >= (int) PRIV (section_count))
+ return;
+
sec = PRIV (sections)[sect];
if (info)
@@ -2450,6 +2491,14 @@ _bfd_vms_slurp_eeom (bfd *abfd)
vms_debug2 ((2, "EEOM\n"));
+ /* PR 21813: Check for an undersized record. */
+ if (PRIV (recrd.buf_size) < sizeof (* eeom))
+ {
+ _bfd_error_handler (_("Corrupt EEOM record - size is too small"));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
PRIV (eom_data).eom_l_total_lps = bfd_getl32 (eeom->total_lps);
PRIV (eom_data).eom_w_comcod = bfd_getl16 (eeom->comcod);
if (PRIV (eom_data).eom_w_comcod > 1)
@@ -2630,6 +2679,9 @@ alpha_vms_object_p (bfd *abfd)
PRIV (recrd.buf_size) = PRIV (recrd.rec_size);
}
+ /* PR 21813: Check for a truncated record. */
+ if (PRIV (recrd.rec_size < test_len))
+ goto error_ret;
/* Read the remaining record. */
remaining = PRIV (recrd.rec_size) - test_len;
to_read = MIN (VMS_BLOCK_SIZE - test_len, remaining);
@@ -5173,7 +5225,7 @@ alpha_vms_slurp_relocs (bfd *abfd)
}
else if (cur_psidx >= 0)
{
- if (PRIV (sections) == NULL)
+ if (PRIV (sections) == NULL || cur_psidx >= (int) PRIV (section_count))
return FALSE;
reloc->sym_ptr_ptr =
PRIV (sections)[cur_psidx]->symbol_ptr_ptr;