From 8bdf0be19d2777565a8b1c88347f65d6a4b8c5fc Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 27 Jul 2017 12:04:50 +0100 Subject: [PATCH] Fix address violation issues encountered when parsing corrupt binaries. PR 21840 * mach-o.c (bfd_mach_o_read_symtab_strtab): Fail if the symtab size is -1. * nlmcode.h (nlm_swap_auxiliary_headers_in): Replace assertion with error return. * section.c (bfd_make_section_with_flags): Fail if the name or bfd are NULL. * vms-alpha.c (bfd_make_section_with_flags): Correct computation of end pointer. (evax_bfd_print_emh): Check for invalid string lengths. --- bfd/ChangeLog | 13 +++++++ bfd/mach-o.c | 3 ++ bfd/nlmcode.h | 4 ++- bfd/section.c | 2 +- bfd/vms-alpha.c | 91 +++++++++++++++++++++++++++++++------------------ bfd/vms-misc.c | 8 ++--- 6 files changed, 82 insertions(+), 39 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index bd50ac56cff..0a4c8526c4d 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,16 @@ +2017-07-27 Nick Clifton + + PR 21840 + * mach-o.c (bfd_mach_o_read_symtab_strtab): Fail if the symtab + size is -1. + * nlmcode.h (nlm_swap_auxiliary_headers_in): Replace assertion + with error return. + * section.c (bfd_make_section_with_flags): Fail if the name or bfd + are NULL. + * vms-alpha.c (bfd_make_section_with_flags): Correct computation + of end pointer. + (evax_bfd_print_emh): Check for invalid string lengths. + 2017-07-25 Nick Clifton * po/fr.po: Updated French translation. diff --git a/bfd/mach-o.c b/bfd/mach-o.c index 1807391d51b..9fe6326a299 100644 --- a/bfd/mach-o.c +++ b/bfd/mach-o.c @@ -3749,6 +3749,9 @@ bfd_mach_o_read_symtab_strtab (bfd *abfd) } else { + /* See PR 21840 for a reproducer. */ + if ((sym->strsize + 1) == 0) + return FALSE; sym->strtab = bfd_alloc (abfd, sym->strsize + 1); if (sym->strtab == NULL) return FALSE; diff --git a/bfd/nlmcode.h b/bfd/nlmcode.h index 6d6aed02c10..350c83e1208 100644 --- a/bfd/nlmcode.h +++ b/bfd/nlmcode.h @@ -351,7 +351,9 @@ nlm_swap_auxiliary_headers_in (bfd *abfd) bfd_byte *contents; bfd_byte *p, *pend; - BFD_ASSERT (hdrLength == 0 && hdr == NULL); + /* See PR 21840 for a reproducer. */ + if (hdrLength != 0 || hdr != NULL) + return FALSE; pos = bfd_tell (abfd); if (bfd_seek (abfd, dataOffset, SEEK_SET) != 0) diff --git a/bfd/section.c b/bfd/section.c index 28eee7f8b3c..811d42a0d02 100644 --- a/bfd/section.c +++ b/bfd/section.c @@ -1240,7 +1240,7 @@ bfd_make_section_with_flags (bfd *abfd, const char *name, struct section_hash_entry *sh; asection *newsect; - if (abfd->output_has_begun) + if (abfd == NULL || name == NULL || abfd->output_has_begun) { bfd_set_error (bfd_error_invalid_operation); return NULL; diff --git a/bfd/vms-alpha.c b/bfd/vms-alpha.c index 610b034ccd0..5595b61e0d0 100644 --- a/bfd/vms-alpha.c +++ b/bfd/vms-alpha.c @@ -903,7 +903,7 @@ _bfd_vms_slurp_ehdr (bfd *abfd) vms_rec = PRIV (recrd.rec); /* PR 17512: file: 62736583. */ - end = vms_rec + PRIV (recrd.buf_size); + end = PRIV (recrd.buf) + PRIV (recrd.buf_size); vms_debug2 ((2, "HDR/EMH\n")); @@ -5737,8 +5737,9 @@ evax_bfd_print_emh (FILE *file, unsigned char *rec, unsigned int rec_len) { struct vms_emh_common *emh = (struct vms_emh_common *)rec; unsigned int subtype; + int extra; - subtype = (unsigned)bfd_getl16 (emh->subtyp); + subtype = (unsigned) bfd_getl16 (emh->subtyp); /* xgettext:c-format */ fprintf (file, _(" EMH %u (len=%u): "), subtype, rec_len); @@ -5749,58 +5750,82 @@ evax_bfd_print_emh (FILE *file, unsigned char *rec, unsigned int rec_len) fprintf (file, _(" Error: The length is less than the length of an EMH record\n")); return; } - + extra = rec_len - sizeof (struct vms_emh_common); + switch (subtype) { case EMH__C_MHD: { - struct vms_emh_mhd *mhd = (struct vms_emh_mhd *)rec; - const char *name; + struct vms_emh_mhd *mhd = (struct vms_emh_mhd *) rec; + const char * name; + const char * nextname; + const char * maxname; + /* PR 21840: Check for invalid lengths. */ + if (rec_len < sizeof (* mhd)) + { + fprintf (file, _(" Error: The record length is less than the size of an EMH_MHD record\n")); + return; + } fprintf (file, _("Module header\n")); fprintf (file, _(" structure level: %u\n"), mhd->strlvl); fprintf (file, _(" max record size: %u\n"), - (unsigned)bfd_getl32 (mhd->recsiz)); + (unsigned) bfd_getl32 (mhd->recsiz)); name = (char *)(mhd + 1); + maxname = (char *) rec + rec_len; + if (name > maxname - 2) + { + fprintf (file, _(" Error: The module name is missing\n")); + return; + } + nextname = name + name[0] + 1; + if (nextname >= maxname) + { + fprintf (file, _(" Error: The module name is too long\n")); + return; + } fprintf (file, _(" module name : %.*s\n"), name[0], name + 1); - name += name[0] + 1; + name = nextname; + if (name > maxname - 2) + { + fprintf (file, _(" Error: The module version is missing\n")); + return; + } + nextname = name + name[0] + 1; + if (nextname >= maxname) + { + fprintf (file, _(" Error: The module version is too long\n")); + return; + } fprintf (file, _(" module version : %.*s\n"), name[0], name + 1); - name += name[0] + 1; - fprintf (file, _(" compile date : %.17s\n"), name); + name = nextname; + if ((maxname - name) < 17 && maxname[-1] != 0) + fprintf (file, _(" Error: The compile date is truncated\n")); + else + fprintf (file, _(" compile date : %.17s\n"), name); } break; + case EMH__C_LNM: - { - fprintf (file, _("Language Processor Name\n")); - fprintf (file, _(" language name: %.*s\n"), - (int)(rec_len - sizeof (struct vms_emh_common)), - (char *)rec + sizeof (struct vms_emh_common)); - } + fprintf (file, _("Language Processor Name\n")); + fprintf (file, _(" language name: %.*s\n"), extra, (char *)(emh + 1)); break; + case EMH__C_SRC: - { - fprintf (file, _("Source Files Header\n")); - fprintf (file, _(" file: %.*s\n"), - (int)(rec_len - sizeof (struct vms_emh_common)), - (char *)rec + sizeof (struct vms_emh_common)); - } + fprintf (file, _("Source Files Header\n")); + fprintf (file, _(" file: %.*s\n"), extra, (char *)(emh + 1)); break; + case EMH__C_TTL: - { - fprintf (file, _("Title Text Header\n")); - fprintf (file, _(" title: %.*s\n"), - (int)(rec_len - sizeof (struct vms_emh_common)), - (char *)rec + sizeof (struct vms_emh_common)); - } + fprintf (file, _("Title Text Header\n")); + fprintf (file, _(" title: %.*s\n"), extra, (char *)(emh + 1)); break; + case EMH__C_CPR: - { - fprintf (file, _("Copyright Header\n")); - fprintf (file, _(" copyright: %.*s\n"), - (int)(rec_len - sizeof (struct vms_emh_common)), - (char *)rec + sizeof (struct vms_emh_common)); - } + fprintf (file, _("Copyright Header\n")); + fprintf (file, _(" copyright: %.*s\n"), extra, (char *)(emh + 1)); break; + default: fprintf (file, _("unhandled emh subtype %u\n"), subtype); break; diff --git a/bfd/vms-misc.c b/bfd/vms-misc.c index 7497f0224da..91e2ec76c22 100644 --- a/bfd/vms-misc.c +++ b/bfd/vms-misc.c @@ -135,8 +135,8 @@ _bfd_hexdump (int level, unsigned char *ptr, int size, int offset) #endif -/* Copy sized string (string with fixed size) to new allocated area - size is string size (size of record) */ +/* Copy sized string (string with fixed size) to new allocated area. + Size is string size (size of record). */ char * _bfd_vms_save_sized_string (unsigned char *str, unsigned int size) @@ -151,8 +151,8 @@ _bfd_vms_save_sized_string (unsigned char *str, unsigned int size) return newstr; } -/* Copy counted string (string with size at first byte) to new allocated area - ptr points to size byte on entry */ +/* Copy counted string (string with size at first byte) to new allocated area. + PTR points to size byte on entry. */ char * _bfd_vms_save_counted_string (unsigned char *ptr, unsigned int maxlen) -- 2.39.2