« Return to Thread: Commit: Add checks for overflowing 4Gb archive symbol table limit

Commit: Add checks for overflowing 4Gb archive symbol table limit

by Nick Clifton :: Rate this Message:

| View in Thread

Hi Guys,

  I am applying the patch below to catch a problem with ar creating
  invalid archives (because the file offsets in the symbol table overflow
  the 32-bits that are available to them).  This is not just a
  theoretical problem - it has now started happening with real libraries
  in real production systems.

  As a side effect of the patch I have also extended readelf's dumping
  of archive symbol tables to include the file offset to the member
  containing the symbols.  This is useful to help track down problems
  like the file offsets overflowing 32-bits.

Cheers
  Nick

bfd/ChangeLog
2012-07-03  Nick Clifton  <nickc@...>

        * archive.c (bsd_write_armap): Catch attempts to create an archive
        with indicies bigger than 4Gb.
        (coff_write_armap): Likewise.

binutils/ChangeLog
2012-07-03  Nick Clifton  <nickc@...>

        * readelf.c (process_archive): Display member indicies when
        dumping index.

Index: bfd/archive.c
===================================================================
RCS file: /cvs/src/src/bfd/archive.c,v
retrieving revision 1.85
diff -u -3 -p -r1.85 archive.c
--- bfd/archive.c 29 Jun 2012 17:36:21 -0000 1.85
+++ bfd/archive.c 3 Jul 2012 14:28:56 -0000
@@ -2405,6 +2405,9 @@ bsd_write_armap (bfd *arch,
   unsigned int count;
   struct ar_hdr hdr;
   long uid, gid;
+  file_ptr max_first_real = 1;
+
+  max_first_real <<= 31;
 
   firstreal = mapsize + elength + sizeof (struct ar_hdr) + SARMAG;
 
@@ -2463,6 +2466,15 @@ bsd_write_armap (bfd *arch,
   while (current != map[count].u.abfd);
  }
 
+      /* The archive file format only has 4 bytes to store the offset
+ of the member.  Check to make sure that firstreal has not grown
+ too big.  */
+      if (firstreal >= max_first_real)
+ {
+  bfd_set_error (bfd_error_file_truncated);
+  return FALSE;
+ }
+      
       last_elt = current;
       H_PUT_32 (arch, map[count].namidx, buf);
       H_PUT_32 (arch, firstreal, buf + BSD_SYMDEF_OFFSET_SIZE);
@@ -2574,7 +2586,7 @@ coff_write_armap (bfd *arch,
   unsigned int ranlibsize = (symbol_count * 4) + 4;
   unsigned int stringsize = stridx;
   unsigned int mapsize = stringsize + ranlibsize;
-  unsigned int archive_member_file_ptr;
+  file_ptr archive_member_file_ptr;
   bfd *current = arch->archive_head;
   unsigned int count;
   struct ar_hdr hdr;
@@ -2625,7 +2637,15 @@ coff_write_armap (bfd *arch,
 
       while (count < symbol_count && map[count].u.abfd == current)
  {
-  if (!bfd_write_bigendian_4byte_int (arch, archive_member_file_ptr))
+  unsigned int offset = (unsigned int) archive_member_file_ptr;
+
+  /* Catch an attempt to grow an archive past its 4Gb limit.  */
+  if (archive_member_file_ptr != (file_ptr) offset)
+    {
+      bfd_set_error (bfd_error_file_truncated);
+      return FALSE;
+    }
+  if (!bfd_write_bigendian_4byte_int (arch, offset))
     return FALSE;
   count++;
  }
Index: binutils/readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.576
diff -u -3 -p -r1.576 readelf.c
--- binutils/readelf.c 29 Jun 2012 07:02:36 -0000 1.576
+++ binutils/readelf.c 3 Jul 2012 14:28:58 -0000
@@ -13459,7 +13459,8 @@ process_archive (char * file_name, FILE
 
                       if (qualified_name != NULL)
                         {
-          printf (_("Binary %s contains:\n"), qualified_name);
+          printf (_("Binary %s at offset 0x%lx contains:\n"),
+  qualified_name, arch.index_array[i]);
           free (qualified_name);
         }
     }


 

 « Return to Thread: Commit: Add checks for overflowing 4Gb archive symbol table limit