diff options
author | Nick Clifton <nickc@redhat.com> | 2017-09-04 16:31:12 +0100 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2017-09-04 16:31:12 +0100 |
commit | deeb3d27c254ad8bf8c3877fa6b61817f56191f5 (patch) | |
tree | ac94a290657a92c24c3ccff49613dd42ad3aa649 | |
parent | a541116faa5716d5c1a4bc9d1567855902b89a87 (diff) | |
download | binutils-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/ChangeLog | 21 | ||||
-rw-r--r-- | bfd/mach-o-aarch64.c | 6 | ||||
-rw-r--r-- | bfd/mach-o-arm.c | 9 | ||||
-rw-r--r-- | bfd/mach-o-i386.c | 7 | ||||
-rw-r--r-- | bfd/mach-o-x86-64.c | 6 | ||||
-rw-r--r-- | bfd/mach-o.c | 2 | ||||
-rw-r--r-- | bfd/mach-o.h | 2 | ||||
-rw-r--r-- | bfd/vms-alpha.c | 62 |
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; |