Bug 15140 - AR produces invalid thin archive which cause binutils to crash
Summary: AR produces invalid thin archive which cause binutils to crash
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: binutils (show other bugs)
Version: 2.24
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-02-13 12:07 UTC by Dmitry Gorbachev
Modified: 2013-02-15 19:32 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
Testcase (123 bytes, text/plain)
2013-02-13 12:07 UTC, Dmitry Gorbachev
Details
Backtrace (662 bytes, text/plain)
2013-02-13 12:09 UTC, Dmitry Gorbachev
Details
Another testcase (98 bytes, application/octet-stream)
2013-02-13 12:11 UTC, Dmitry Gorbachev
Details
Backtrace from readelf (316 bytes, text/plain)
2013-02-13 12:12 UTC, Dmitry Gorbachev
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Dmitry Gorbachev 2013-02-13 12:07:49 UTC
Created attachment 6865 [details]
Testcase

Says binutils documentation:

> Thin archives are also flattened, so that adding
> one or more archives to a thin archive will add
> the elements of the nested archive individually.

> If it already exists and is a regular archive,
> the existing members must be present in the same
> directory as archive.
Comment 1 Dmitry Gorbachev 2013-02-13 12:09:06 UTC
Created attachment 6866 [details]
Backtrace
Comment 2 Dmitry Gorbachev 2013-02-13 12:11:03 UTC
Created attachment 6867 [details]
Another testcase

A slightly modified testcase causes SIGSEGV in readelf.
Comment 3 Dmitry Gorbachev 2013-02-13 12:12:21 UTC
Created attachment 6868 [details]
Backtrace from readelf
Comment 4 Dmitry Gorbachev 2013-02-13 12:15:53 UTC
Additional comment about the 2nd testcase:

$ strip libbarfoo.a

causes the archive to be empty.
Comment 5 cvs-commit@gcc.gnu.org 2013-02-15 14:37:47 UTC
CVSROOT:	/cvs/src
Module name:	src
Changes by:	nickc@sourceware.org	2013-02-15 14:37:39

Modified files:
	binutils       : ChangeLog readelf.c ar.c elfcomm.c 
	bfd            : ChangeLog archive.c 
	binutils/doc   : binutils.texi 

Log message:
	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.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/src/binutils/ChangeLog.diff?cvsroot=src&r1=1.1990&r2=1.1991
http://sourceware.org/cgi-bin/cvsweb.cgi/src/binutils/readelf.c.diff?cvsroot=src&r1=1.594&r2=1.595
http://sourceware.org/cgi-bin/cvsweb.cgi/src/binutils/ar.c.diff?cvsroot=src&r1=1.86&r2=1.87
http://sourceware.org/cgi-bin/cvsweb.cgi/src/binutils/elfcomm.c.diff?cvsroot=src&r1=1.4&r2=1.5
http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/ChangeLog.diff?cvsroot=src&r1=1.5966&r2=1.5967
http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/archive.c.diff?cvsroot=src&r1=1.95&r2=1.96
http://sourceware.org/cgi-bin/cvsweb.cgi/src/binutils/doc/binutils.texi.diff?cvsroot=src&r1=1.197&r2=1.198
Comment 6 Nick Clifton 2013-02-15 14:38:22 UTC
Hi Dmitry,

  The problem here is not the flattening of thin archives, but rather the fact that you are trying to convert a normal, non-thin, archive into a thin one.  This is not supported, but ar should have produced an error message when the attempt was made.

  I have checked in a patch which fixes ar so that it will produce an error message.  It also updates the documentation to make it clear that archives cannot be converted between normal and thin types.  Finally the patch fixes readelf so that it no longer segfaults on the corrupted archive and nm so that it no longer goes into an infinite loop trying to read its symbol table.

Cheers
  Nick
Comment 7 H.J. Lu 2013-02-15 17:22:47 UTC
This patch:

@@ -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))
     {

has 2 problems:

1. It sets prev_filepos on success.  The next call on the same
filepos returns NULL.
2. It checks prev_filepos without checking if archive is the same.

It caused PR 15151.
Comment 8 H.J. Lu 2013-02-15 19:32:08 UTC
A different fix checked in.