From a043396b72d17ae87267b534aa98457a0702f5c8 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Fri, 15 Feb 2013 14:37:39 +0000 Subject: [PATCH] PR binutils/15140 * ar.c (open_inarch): Fail on attempts to convert a normal archive to a thin archive or vice versa. * elfcomm.c (make_qualified_name): Handle corrupted thin archives. * readelf.c (process_archive): Likewise. * doc/binutils.texi: Clarify documentation describing thin archives. * archive.c (_bfd_get_elt_at_filepos): Prevent an infinite loop accessing a corrupt nested archive. --- bfd/ChangeLog | 6 ++++++ bfd/archive.c | 12 +++++++++--- binutils/ChangeLog | 11 +++++++++++ binutils/ar.c | 23 ++++++++++++++++++++--- binutils/doc/binutils.texi | 26 ++++++++++++++++---------- binutils/elfcomm.c | 28 +++++++++++++++++++++------- binutils/readelf.c | 9 +++++++++ 7 files changed, 92 insertions(+), 23 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 21c9396..b65b234 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,9 @@ +2013-02-15 Nick Clifton + + PR binutils/15140 + * archive.c (_bfd_get_elt_at_filepos): Prevent an infinite loop + accessing a corrupt nested archive. + 2013-02-13 Richard Sandiford * elfxx-mips.c (mips_got_page_ref): New structure. diff --git a/bfd/archive.c b/bfd/archive.c index e4183ea..4b6a81c 100644 --- a/bfd/archive.c +++ b/bfd/archive.c @@ -1,7 +1,5 @@ /* BFD back-end for archive files (libraries). - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, - 2012 Free Software Foundation, Inc. + Copyright 1990-2013 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. @@ -619,6 +617,7 @@ _bfd_append_relative_path (bfd *arch, char *elt_name) bfd * _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) { + static file_ptr prev_filepos; struct areltdata *new_areldata; bfd *n_nfd; char *filename; @@ -626,6 +625,12 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos); if (n_nfd) return n_nfd; + /* PR15140: Prevent an inifnite recursion scanning a malformed nested archive. */ + if (filepos == prev_filepos) + { + bfd_set_error (bfd_error_malformed_archive); + return NULL; + } if (0 > bfd_seek (archive, filepos, SEEK_SET)) return NULL; @@ -634,6 +639,7 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos) return NULL; filename = new_areldata->filename; + prev_filepos = filepos; if (bfd_is_thin_archive (archive)) { diff --git a/binutils/ChangeLog b/binutils/ChangeLog index d2e6dd0..06f5dd5 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -4,6 +4,17 @@ 2013-02-15 Nick Clifton + PR binutils/15140 + * ar.c (open_inarch): Fail on attempts to convert a normal archive + to a thin archive or vice versa. + * elfcomm.c (make_qualified_name): Handle corrupted thin + archives. + * readelf.c (process_archive): Likewise. + * doc/binutils.texi: Clarify documentation describing thin + archives. + +2013-02-15 Nick Clifton + PR binutils/15033 * objcopy.c (enum change_action): Delete. (struct section_list): Delete remove, copy, change_vma, change_lma diff --git a/binutils/ar.c b/binutils/ar.c index 0aa1ba3..c424038 100644 --- a/binutils/ar.c +++ b/binutils/ar.c @@ -1,7 +1,5 @@ /* ar.c - Archive modify and extract. - Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 - Free Software Foundation, Inc. + Copyright 1991-2013 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -918,6 +916,25 @@ open_inarch (const char *archive_filename, const char *file) xexit (1); } + if ((operation == replace || operation == quick_append) + && bfd_openr_next_archived_file (arch, NULL) != NULL) + { + /* PR 15140: Catch attempts to convert a normal + archive into a thin archive or vice versa. */ + if (make_thin_archive && ! bfd_is_thin_archive (arch)) + { + fatal (_("Cannot convert existing library %s to thin format"), + bfd_get_filename (arch)); + goto bloser; + } + else if (! make_thin_archive && bfd_is_thin_archive (arch)) + { + fatal (_("Cannot convert existing thin library %s to normal format"), + bfd_get_filename (arch)); + goto bloser; + } + } + last_one = &(arch->archive_next); /* Read all the contents right away, regardless. */ for (next_one = bfd_openr_next_archived_file (arch, NULL); diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index d733fdb..0bb1d92 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -10,10 +10,7 @@ @copying @c man begin COPYRIGHT -Copyright @copyright{} 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, -1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, -2010, 2011, 2012, 2013 -Free Software Foundation, Inc. +Copyright @copyright{} 1991-2013 Free Software Foundation, Inc. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 @@ -221,12 +218,21 @@ table. If an archive lacks the table, another form of @command{ar} called @cindex thin archives @sc{gnu} @command{ar} can optionally create a @emph{thin} archive, which contains a symbol index and references to the original copies -of the member files of the archives. Such an archive is useful -for building libraries for use within a local build, where the -relocatable objects are expected to remain available, and copying the -contents of each object would only waste time and space. Thin archives -are also @emph{flattened}, so that adding one or more archives to a -thin archive will add the elements of the nested archive individually. +of the member files of the archive. This is useful for building +libraries for use within a local build tree, where the relocatable +objects are expected to remain available, and copying the contents of +each object would only waste time and space. + +An archive can either be @emph{thin} or it can be normal. It cannot +be both at the same time. Once an archive is created its format +cannot be changed without first deleting it and then creating a new +archive in its place. + +Thin archives are also @emph{flattened}, so that adding one thin +archive to another thin archive does not nest it, as would happen with +a normal archive. Instead the elements of the first archive are added +individually to the second archive. + The paths to the elements of the archive are stored relative to the archive itself. diff --git a/binutils/elfcomm.c b/binutils/elfcomm.c index 64d4b213..1179a1a 100644 --- a/binutils/elfcomm.c +++ b/binutils/elfcomm.c @@ -1,6 +1,5 @@ /* elfcomm.c -- common code for ELF format file. - Copyright 2010 - Free Software Foundation, Inc. + Copyright 2010-2013 Free Software Foundation, Inc. Originally developed by Eric Youngdale Modifications by Nick Clifton @@ -690,12 +689,20 @@ make_qualified_name (struct archive_info * arch, struct archive_info * nested_arch, const char *member_name) { + const char * error_name = _(""); size_t len; char * name; len = strlen (arch->file_name) + strlen (member_name) + 3; - if (arch->is_thin_archive && arch->nested_member_origin != 0) - len += strlen (nested_arch->file_name) + 2; + if (arch->is_thin_archive + && arch->nested_member_origin != 0) + { + /* PR 15140: Allow for corrupt thin archives. */ + if (nested_arch->file_name) + len += strlen (nested_arch->file_name) + 2; + else + len += strlen (error_name) + 2; + } name = (char *) malloc (len); if (name == NULL) @@ -704,9 +711,16 @@ make_qualified_name (struct archive_info * arch, return NULL; } - if (arch->is_thin_archive && arch->nested_member_origin != 0) - snprintf (name, len, "%s[%s(%s)]", arch->file_name, - nested_arch->file_name, member_name); + if (arch->is_thin_archive + && arch->nested_member_origin != 0) + { + if (nested_arch->file_name) + snprintf (name, len, "%s[%s(%s)]", arch->file_name, + nested_arch->file_name, member_name); + else + snprintf (name, len, "%s[%s(%s)]", arch->file_name, + error_name, member_name); + } else if (arch->is_thin_archive) snprintf (name, len, "%s[%s]", arch->file_name, member_name); else diff --git a/binutils/readelf.c b/binutils/readelf.c index 7710079..c7bd05f 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -13975,6 +13975,15 @@ process_archive (char * file_name, FILE * file, bfd_boolean is_thin_archive) } else if (is_thin_archive) { + /* PR 15140: Allow for corrupt thin archives. */ + if (nested_arch.file == NULL) + { + error (_("%s: contains corrupt thin archive: %s\n"), + file_name, name); + ret = 1; + break; + } + /* This is a proxy for a member of a nested archive. */ archive_file_offset = arch.nested_member_origin + sizeof arch.arhdr; -- 2.7.4