X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Farchive.c;h=9d63849a483d5cd5c5ad40eb6b811bae2c9ae813;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=ccc09ad49f232c1b856bab22c7a067f13c80be70;hpb=00f93c449228e69f2161405b1f49b406e88785f0;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/archive.c b/bfd/archive.c index ccc09ad49f..9d63849a48 100644 --- a/bfd/archive.c +++ b/bfd/archive.c @@ -1,5 +1,5 @@ /* BFD back-end for archive files (libraries). - Copyright (C) 1990-2019 Free Software Foundation, Inc. + Copyright (C) 1990-2020 Free Software Foundation, Inc. Written by Cygnus Support. Mostly Gumby Henkel-Wallace's fault. This file is part of BFD, the Binary File Descriptor library. @@ -212,7 +212,7 @@ _bfd_ar_sizepad (char *p, size_t n, bfd_size_type size) bfd_boolean _bfd_generic_mkarchive (bfd *abfd) { - bfd_size_type amt = sizeof (struct artdata); + size_t amt = sizeof (struct artdata); abfd->tdata.aout_ar_data = (struct artdata *) bfd_zalloc (abfd, amt); if (bfd_ardata (abfd) == NULL) @@ -403,7 +403,7 @@ find_nested_archive (const char *filename, bfd *arch_bfd) bfd *abfd; /* PR 15140: Don't allow a nested archive pointing to itself. */ - if (filename_cmp (filename, arch_bfd->filename) == 0) + if (filename_cmp (filename, bfd_get_filename (arch_bfd)) == 0) { bfd_set_error (bfd_error_malformed_archive); return NULL; @@ -413,7 +413,7 @@ find_nested_archive (const char *filename, bfd *arch_bfd) abfd != NULL; abfd = abfd->archive_next) { - if (filename_cmp (filename, abfd->filename) == 0) + if (filename_cmp (filename, bfd_get_filename (abfd)) == 0) return abfd; } abfd = open_nested_file (filename, arch_bfd); @@ -488,6 +488,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) bfd_size_type parsed_size; struct areltdata *ared; char *filename = NULL; + ufile_ptr filesize; bfd_size_type namelen = 0; bfd_size_type allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr); char *allocptr = 0; @@ -538,11 +539,19 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) { /* BSD-4.4 extended name */ namelen = atoi (&hdr.ar_name[3]); + filesize = bfd_get_file_size (abfd); + if (namelen > parsed_size + || namelen > -allocsize - 2 + || (filesize != 0 && namelen > filesize)) + { + bfd_set_error (bfd_error_malformed_archive); + return NULL; + } allocsize += namelen + 1; parsed_size -= namelen; extra_size = namelen; - allocptr = (char *) bfd_zmalloc (allocsize); + allocptr = (char *) bfd_malloc (allocsize); if (allocptr == NULL) return NULL; filename = (allocptr @@ -586,13 +595,13 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) if (!allocptr) { - allocptr = (char *) bfd_zmalloc (allocsize); + allocptr = (char *) bfd_malloc (allocsize); if (allocptr == NULL) return NULL; } + memset (allocptr, 0, sizeof (struct areltdata)); ared = (struct areltdata *) allocptr; - ared->arch_header = allocptr + sizeof (struct areltdata); memcpy (ared->arch_header, &hdr, sizeof (struct ar_hdr)); ared->parsed_size = parsed_size; @@ -619,7 +628,7 @@ _bfd_generic_read_ar_hdr_mag (bfd *abfd, const char *mag) char * _bfd_append_relative_path (bfd *arch, char *elt_name) { - const char *arch_name = arch->filename; + const char *arch_name = bfd_get_filename (arch); const char *base_name = lbasename (arch_name); size_t prefix_len; char *filename; @@ -728,8 +737,7 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) else { n_bfd->origin = n_bfd->proxy_origin; - n_bfd->filename = bfd_strdup (filename); - if (n_bfd->filename == NULL) + if (!bfd_set_filename (n_bfd, filename)) goto out; } @@ -842,12 +850,12 @@ _bfd_noarchive_openr_next_archived_file (bfd *archive, return (bfd *) _bfd_ptr_bfd_null_error (archive); } -const bfd_target * +bfd_cleanup bfd_generic_archive_p (bfd *abfd) { struct artdata *tdata_hold; char armag[SARMAG + 1]; - bfd_size_type amt; + size_t amt; if (bfd_bread (armag, SARMAG, abfd) != SARMAG) { @@ -924,7 +932,7 @@ bfd_generic_archive_p (bfd *abfd) } } - return abfd->xvec; + return _bfd_no_cleanup; } /* Some constants for a 32 bit BSD archive structure. We do not @@ -951,11 +959,12 @@ static bfd_boolean do_slurp_bsd_armap (bfd *abfd) { struct areltdata *mapdata; - unsigned int counter; + size_t counter; bfd_byte *raw_armap, *rbase; struct artdata *ardata = bfd_ardata (abfd); char *stringbase; - bfd_size_type parsed_size, amt; + bfd_size_type parsed_size; + size_t amt, string_size; carsym *set; mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); @@ -965,45 +974,51 @@ do_slurp_bsd_armap (bfd *abfd) free (mapdata); /* PR 17512: file: 883ff754. */ /* PR 17512: file: 0458885f. */ - if (parsed_size < 4) - return FALSE; - - raw_armap = (bfd_byte *) bfd_zalloc (abfd, parsed_size); - if (raw_armap == NULL) - return FALSE; - - if (bfd_bread (raw_armap, parsed_size, abfd) != parsed_size) + if (parsed_size < BSD_SYMDEF_COUNT_SIZE + BSD_STRING_COUNT_SIZE) { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_malformed_archive); - byebye: - bfd_release (abfd, raw_armap); + bfd_set_error (bfd_error_malformed_archive); return FALSE; } - ardata->symdef_count = H_GET_32 (abfd, raw_armap) / BSD_SYMDEF_SIZE; - if (ardata->symdef_count * BSD_SYMDEF_SIZE > - parsed_size - BSD_SYMDEF_COUNT_SIZE) + raw_armap = (bfd_byte *) _bfd_alloc_and_read (abfd, parsed_size, parsed_size); + if (raw_armap == NULL) + return FALSE; + + parsed_size -= BSD_SYMDEF_COUNT_SIZE + BSD_STRING_COUNT_SIZE; + amt = H_GET_32 (abfd, raw_armap); + if (amt > parsed_size + || amt % BSD_SYMDEF_SIZE != 0) { /* Probably we're using the wrong byte ordering. */ bfd_set_error (bfd_error_wrong_format); - goto byebye; + goto release_armap; } rbase = raw_armap + BSD_SYMDEF_COUNT_SIZE; - stringbase = ((char *) rbase - + ardata->symdef_count * BSD_SYMDEF_SIZE - + BSD_STRING_COUNT_SIZE); - amt = ardata->symdef_count * sizeof (carsym); + stringbase = (char *) rbase + amt + BSD_STRING_COUNT_SIZE; + string_size = parsed_size - amt; + + ardata->symdef_count = amt / BSD_SYMDEF_SIZE; + if (_bfd_mul_overflow (ardata->symdef_count, sizeof (carsym), &amt)) + { + bfd_set_error (bfd_error_no_memory); + goto release_armap; + } ardata->symdefs = (struct carsym *) bfd_alloc (abfd, amt); if (!ardata->symdefs) - return FALSE; + goto release_armap; for (counter = 0, set = ardata->symdefs; counter < ardata->symdef_count; counter++, set++, rbase += BSD_SYMDEF_SIZE) { - set->name = H_GET_32 (abfd, rbase) + stringbase; + unsigned nameoff = H_GET_32 (abfd, rbase); + if (nameoff >= string_size) + { + bfd_set_error (bfd_error_malformed_archive); + goto release_armap; + } + set->name = stringbase + nameoff; set->file_offset = H_GET_32 (abfd, rbase + BSD_SYMDEF_OFFSET_SIZE); } @@ -1015,6 +1030,12 @@ do_slurp_bsd_armap (bfd *abfd) to be allocated on an objalloc anyway... */ abfd->has_armap = TRUE; return TRUE; + + release_armap: + ardata->symdef_count = 0; + ardata->symdefs = NULL; + bfd_release (abfd, raw_armap); + return FALSE; } /* Read a COFF archive symbol table. Returns FALSE on error, TRUE @@ -1030,12 +1051,12 @@ do_slurp_coff_armap (bfd *abfd) char *stringend; bfd_size_type stringsize; bfd_size_type parsed_size; + ufile_ptr filesize; + size_t nsymz, carsym_size, ptrsize, i; carsym *carsyms; - bfd_size_type nsymz; /* Number of symbols in armap. */ bfd_vma (*swap) (const void *); - char int_buf[sizeof (long)]; - bfd_size_type carsym_size, ptrsize; - unsigned int i; + char int_buf[4]; + struct areltdata *tmp; mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); if (mapdata == NULL) @@ -1044,47 +1065,54 @@ do_slurp_coff_armap (bfd *abfd) free (mapdata); if (bfd_bread (int_buf, 4, abfd) != 4) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_malformed_archive); - return FALSE; - } + return FALSE; + /* It seems that all numeric information in a coff archive is always - in big endian format, nomatter the host or target. */ + in big endian format, no matter the host or target. */ swap = bfd_getb32; nsymz = bfd_getb32 (int_buf); - stringsize = parsed_size - (4 * nsymz) - 4; /* The coff armap must be read sequentially. So we construct a bsd-style one in core all at once, for simplicity. */ - if (nsymz > ~ (bfd_size_type) 0 / sizeof (carsym)) - return FALSE; + if (_bfd_mul_overflow (nsymz, sizeof (carsym), &carsym_size)) + { + bfd_set_error (bfd_error_no_memory); + return FALSE; + } + + filesize = bfd_get_file_size (abfd); + ptrsize = 4 * nsymz; + if ((filesize != 0 && parsed_size > filesize) + || parsed_size < 4 + || parsed_size - 4 < ptrsize) + { + bfd_set_error (bfd_error_malformed_archive); + return FALSE; + } - carsym_size = (nsymz * sizeof (carsym)); - ptrsize = (4 * nsymz); + stringsize = parsed_size - ptrsize - 4; if (carsym_size + stringsize + 1 <= carsym_size) + { + bfd_set_error (bfd_error_no_memory); + return FALSE; + } + + /* Allocate and read in the raw offsets. */ + raw_armap = (int *) _bfd_malloc_and_read (abfd, ptrsize, ptrsize); + if (raw_armap == NULL) return FALSE; - ardata->symdefs = (struct carsym *) bfd_zalloc (abfd, - carsym_size + stringsize + 1); + ardata->symdefs = (struct carsym *) bfd_alloc (abfd, + carsym_size + stringsize + 1); if (ardata->symdefs == NULL) - return FALSE; + goto free_armap; carsyms = ardata->symdefs; stringbase = ((char *) ardata->symdefs) + carsym_size; - /* Allocate and read in the raw offsets. */ - raw_armap = (int *) bfd_alloc (abfd, ptrsize); - if (raw_armap == NULL) + if (bfd_bread (stringbase, stringsize, abfd) != stringsize) goto release_symdefs; - if (bfd_bread (raw_armap, ptrsize, abfd) != ptrsize - || (bfd_bread (stringbase, stringsize, abfd) != stringsize)) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_malformed_archive); - goto release_raw_armap; - } /* OK, build the carsyms. */ stringend = stringbase + stringsize; @@ -1104,34 +1132,29 @@ do_slurp_coff_armap (bfd *abfd) ardata->first_file_filepos = bfd_tell (abfd); /* Pad to an even boundary if you have to. */ ardata->first_file_filepos += (ardata->first_file_filepos) % 2; + if (bfd_seek (abfd, ardata->first_file_filepos, SEEK_SET) != 0) + goto release_symdefs; abfd->has_armap = TRUE; - bfd_release (abfd, raw_armap); + free (raw_armap); /* Check for a second archive header (as used by PE). */ - { - struct areltdata *tmp; - - bfd_seek (abfd, ardata->first_file_filepos, SEEK_SET); - tmp = (struct areltdata *) _bfd_read_ar_hdr (abfd); - if (tmp != NULL) - { - if (tmp->arch_header[0] == '/' - && tmp->arch_header[1] == ' ') - { - ardata->first_file_filepos += - (tmp->parsed_size + sizeof (struct ar_hdr) + 1) & ~(unsigned) 1; - } - free (tmp); - } - } + tmp = (struct areltdata *) _bfd_read_ar_hdr (abfd); + if (tmp != NULL) + { + if (tmp->arch_header[0] == '/' + && tmp->arch_header[1] == ' ') + ardata->first_file_filepos + += (tmp->parsed_size + sizeof (struct ar_hdr) + 1) & ~(unsigned) 1; + free (tmp); + } return TRUE; -release_raw_armap: - bfd_release (abfd, raw_armap); -release_symdefs: + release_symdefs: bfd_release (abfd, (ardata)->symdefs); + free_armap: + free (raw_armap); return FALSE; } @@ -1208,8 +1231,6 @@ bfd_boolean _bfd_slurp_extended_name_table (bfd *abfd) { char nextname[17]; - struct areltdata *namedata; - bfd_size_type amt; /* FIXME: Formatting sucks here, and in case of failure of BFD_READ, we probably don't want to return TRUE. */ @@ -1218,6 +1239,10 @@ _bfd_slurp_extended_name_table (bfd *abfd) if (bfd_bread (nextname, 16, abfd) == 16) { + struct areltdata *namedata; + bfd_size_type amt; + ufile_ptr filesize; + if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0) return FALSE; @@ -1233,12 +1258,16 @@ _bfd_slurp_extended_name_table (bfd *abfd) if (namedata == NULL) return FALSE; + filesize = bfd_get_file_size (abfd); amt = namedata->parsed_size; - if (amt + 1 == 0) - goto byebye; + if (amt + 1 == 0 || (filesize != 0 && amt > filesize)) + { + bfd_set_error (bfd_error_malformed_archive); + goto byebye; + } bfd_ardata (abfd)->extended_names_size = amt; - bfd_ardata (abfd)->extended_names = (char *) bfd_zalloc (abfd, amt + 1); + bfd_ardata (abfd)->extended_names = (char *) bfd_alloc (abfd, amt + 1); if (bfd_ardata (abfd)->extended_names == NULL) { byebye: @@ -1256,6 +1285,7 @@ _bfd_slurp_extended_name_table (bfd *abfd) bfd_ardata (abfd)->extended_names = NULL; goto byebye; } + bfd_ardata (abfd)->extended_names[amt] = 0; /* Since the archive is supposed to be printable if it contains text, the entries in the list are newline-padded, not null @@ -1299,6 +1329,9 @@ normalize (bfd *abfd, const char *file) const char *last; char *copy; + if (abfd->flags & BFD_ARCHIVE_FULL_PATH) + return file; + first = file + strlen (file) - 1; last = first + 1; @@ -1326,8 +1359,10 @@ normalize (bfd *abfd, const char *file) #else static const char * -normalize (bfd *abfd ATTRIBUTE_UNUSED, const char *file) +normalize (bfd *abfd, const char *file) { + if (abfd->flags & BFD_ARCHIVE_FULL_PATH) + return file; return lbasename (file); } #endif @@ -1433,8 +1468,7 @@ adjust_relative_path (const char * path, const char * ref_path) if (len > pathbuf_len) { - if (pathbuf != NULL) - free (pathbuf); + free (pathbuf); pathbuf_len = 0; pathbuf = (char *) bfd_malloc (len); if (pathbuf == NULL) @@ -1528,13 +1562,13 @@ _bfd_construct_extended_name_table (bfd *abfd, if (bfd_is_thin_archive (abfd)) { - const char *filename = current->filename; + const char *filename = bfd_get_filename (current); /* If the element being added is a member of another archive (i.e., we are flattening), use the containing archive's name. */ if (current->my_archive && ! bfd_is_thin_archive (current->my_archive)) - filename = current->my_archive->filename; + filename = bfd_get_filename (current->my_archive); /* If the path is the same as the previous path seen, reuse it. This can happen when flattening a thin @@ -1547,8 +1581,8 @@ _bfd_construct_extended_name_table (bfd *abfd, /* If the path is relative, adjust it relative to the containing archive. */ if (! IS_ABSOLUTE_PATH (filename) - && ! IS_ABSOLUTE_PATH (abfd->filename)) - normal = adjust_relative_path (filename, abfd->filename); + && ! IS_ABSOLUTE_PATH (bfd_get_filename (abfd))) + normal = adjust_relative_path (filename, bfd_get_filename (abfd)); else normal = filename; @@ -1562,7 +1596,7 @@ _bfd_construct_extended_name_table (bfd *abfd, continue; } - normal = normalize (current, current->filename); + normal = normalize (abfd, bfd_get_filename (current)); if (normal == NULL) return FALSE; @@ -1602,7 +1636,7 @@ _bfd_construct_extended_name_table (bfd *abfd, if (total_namelen == 0) return TRUE; - *tabloc = (char *) bfd_zalloc (abfd, total_namelen); + *tabloc = (char *) bfd_alloc (abfd, total_namelen); if (*tabloc == NULL) return FALSE; @@ -1619,7 +1653,7 @@ _bfd_construct_extended_name_table (bfd *abfd, const char *normal; unsigned int thislen; long stroff; - const char *filename = current->filename; + const char *filename = bfd_get_filename (current); if (bfd_is_thin_archive (abfd)) { @@ -1627,7 +1661,7 @@ _bfd_construct_extended_name_table (bfd *abfd, (i.e., we are flattening), use the containing archive's name. */ if (current->my_archive && ! bfd_is_thin_archive (current->my_archive)) - filename = current->my_archive->filename; + filename = bfd_get_filename (current->my_archive); /* If the path is the same as the previous path seen, reuse it. This can happen when flattening a thin archive that contains other archives. @@ -1636,14 +1670,14 @@ _bfd_construct_extended_name_table (bfd *abfd, if (last_filename && filename_cmp (last_filename, filename) == 0) normal = last_filename; else if (! IS_ABSOLUTE_PATH (filename) - && ! IS_ABSOLUTE_PATH (abfd->filename)) - normal = adjust_relative_path (filename, abfd->filename); + && ! IS_ABSOLUTE_PATH (bfd_get_filename (abfd))) + normal = adjust_relative_path (filename, bfd_get_filename (abfd)); else normal = filename; } else { - normal = normalize (current, filename); + normal = normalize (abfd, filename); if (normal == NULL) return FALSE; } @@ -1659,16 +1693,14 @@ _bfd_construct_extended_name_table (bfd *abfd, stroff = last_stroff; else { - strcpy (strptr, normal); - if (! trailing_slash) - strptr[thislen] = ARFMAG[1]; - else - { - strptr[thislen] = '/'; - strptr[thislen + 1] = ARFMAG[1]; - } + last_filename = filename; stroff = strptr - *tabloc; last_stroff = stroff; + memcpy (strptr, normal, thislen); + strptr += thislen; + if (trailing_slash) + *strptr++ = '/'; + *strptr++ = ARFMAG[1]; } hdr->ar_name[0] = ar_padchar (current); if (bfd_is_thin_archive (abfd) && current->origin > 0) @@ -1681,13 +1713,6 @@ _bfd_construct_extended_name_table (bfd *abfd, } else _bfd_ar_spacepad (hdr->ar_name + 1, maxname - 1, "%-ld", stroff); - if (normal != last_filename) - { - strptr += thislen + 1; - if (trailing_slash) - ++strptr; - last_filename = filename; - } } } @@ -1714,7 +1739,7 @@ _bfd_archive_bsd44_construct_extended_name_table (bfd *abfd, current != NULL; current = current->archive_next) { - const char *normal = normalize (current, current->filename); + const char *normal = normalize (abfd, bfd_get_filename (current)); int has_space = 0; unsigned int len; @@ -1760,7 +1785,7 @@ _bfd_bsd44_write_ar_hdr (bfd *archive, bfd *abfd) if (is_bsd44_extended_name (hdr->ar_name)) { /* This is a BSD 4.4 extended name. */ - const char *fullname = normalize (abfd, abfd->filename); + const char *fullname = normalize (abfd, bfd_get_filename (abfd)); unsigned int len = strlen (fullname); unsigned int padded_len = (len + 3) & ~3; @@ -1836,7 +1861,7 @@ bfd_ar_hdr_from_filesystem (bfd *abfd, const char *filename, bfd *member) struct stat status; struct areltdata *ared; struct ar_hdr *hdr; - bfd_size_type amt; + size_t amt; if (member && (member->flags & BFD_IN_MEMORY) != 0) { @@ -2112,13 +2137,15 @@ _bfd_write_archive_contents (bfd *arch) if (!current->arelt_data) { current->arelt_data = - bfd_ar_hdr_from_filesystem (arch, current->filename, current); + bfd_ar_hdr_from_filesystem (arch, bfd_get_filename (current), + current); if (!current->arelt_data) goto input_err; /* Put in the file name. */ BFD_SEND (arch, _bfd_truncate_arname, - (arch, current->filename, (char *) arch_hdr (current))); + (arch, bfd_get_filename (current), + (char *) arch_hdr (current))); } if (makemap && ! hasobjects) @@ -2186,17 +2213,13 @@ _bfd_write_archive_contents (bfd *arch) while (remaining) { - unsigned int amt = DEFAULT_BUFFERSIZE; + size_t amt = DEFAULT_BUFFERSIZE; if (amt > remaining) amt = remaining; errno = 0; if (bfd_bread (buffer, amt, current) != amt) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_file_truncated); - goto input_err; - } + goto input_err; if (bfd_bwrite (buffer, amt, arch) != amt) return FALSE; remaining -= amt; @@ -2250,7 +2273,7 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) asymbol **syms = NULL; long syms_max = 0; bfd_boolean ret; - bfd_size_type amt; + size_t amt; static bfd_boolean report_plugin_err = TRUE; /* Dunno if this is the best place for this info... */ @@ -2271,7 +2294,7 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) /* Drop all the files called __.SYMDEF, we're going to make our own. */ while (arch->archive_head - && strcmp (arch->archive_head->filename, "__.SYMDEF") == 0) + && strcmp (bfd_get_filename (arch->archive_head), "__.SYMDEF") == 0) arch->archive_head = arch->archive_head->archive_next; /* Map over each element. */ @@ -2302,8 +2325,7 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) { if (storage > syms_max) { - if (syms_max > 0) - free (syms); + free (syms); syms_max = storage; syms = (asymbol **) bfd_malloc (syms_max); if (syms == NULL) @@ -2384,20 +2406,16 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength) ret = BFD_SEND (arch, write_armap, (arch, elength, map, orl_count, stridx)); - if (syms_max > 0) - free (syms); - if (map != NULL) - free (map); + free (syms); + free (map); if (first_name != NULL) bfd_release (arch, first_name); return ret; error_return: - if (syms_max > 0) - free (syms); - if (map != NULL) - free (map); + free (syms); + free (map); if (first_name != NULL) bfd_release (arch, first_name); @@ -2472,7 +2490,7 @@ _bfd_bsd_write_armap (bfd *arch, { struct stat statbuf; - if (stat (arch->filename, &statbuf) == 0) + if (stat (bfd_get_filename (arch), &statbuf) == 0) bfd_ardata (arch)->armap_timestamp = (statbuf.st_mtime + ARMAP_TIME_OFFSET); uid = getuid();