[binutils-gdb] readelf large memory allocation

Alan Modra amodra@sourceware.org
Sat Mar 14 06:54:49 GMT 2020


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=780f96aed2b4db1014e8fa2b50118676d8af0e46

commit 780f96aed2b4db1014e8fa2b50118676d8af0e46
Author: Alan Modra <amodra@gmail.com>
Date:   Sat Mar 14 11:50:22 2020 +1030

    readelf large memory allocation
    
            * elfcomm.h (setup_archive): Update prototype.
            * elfcomm.c (setup_archive): Add file_size parameter and sanity
            check longnames_size.
            (setup_nested_archive): Get file size and pass to setup_archive.
            * elfedit.c (process_archive): Likewise.
            * readelf.c (process_archive): Pass filedata->file_size to
            setup_archive.

Diff:
---
 binutils/ChangeLog | 10 ++++++++++
 binutils/elfcomm.c | 12 ++++++++----
 binutils/elfcomm.h |  2 +-
 binutils/elfedit.c |  5 ++++-
 binutils/readelf.c |  3 ++-
 5 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 9a64b0de245..5101b8c9912 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,13 @@
+2020-03-14  Alan Modra  <amodra@gmail.com>
+
+	* elfcomm.h (setup_archive): Update prototype.
+	* elfcomm.c (setup_archive): Add file_size parameter and sanity
+	check longnames_size.
+	(setup_nested_archive): Get file size and pass to setup_archive.
+	* elfedit.c (process_archive): Likewise.
+	* readelf.c (process_archive): Pass filedata->file_size to
+	setup_archive.
+
 2020-03-14  Alan Modra  <amodra@gmail.com>
 
 	* readelf.c (dump_section_as_strings): Free memory on error exit.
diff --git a/binutils/elfcomm.c b/binutils/elfcomm.c
index 3060ff178e1..e5c6a32c6da 100644
--- a/binutils/elfcomm.c
+++ b/binutils/elfcomm.c
@@ -607,8 +607,8 @@ process_archive_index_and_symbols (struct archive_info *  arch,
 
 int
 setup_archive (struct archive_info *arch, const char *file_name,
-	       FILE *file, bfd_boolean is_thin_archive,
-	       bfd_boolean read_symbols)
+	       FILE *file, bfd_size_type file_size,
+	       bfd_boolean is_thin_archive, bfd_boolean read_symbols)
 {
   size_t got;
 
@@ -671,7 +671,8 @@ setup_archive (struct archive_info *arch, const char *file_name,
 	  return 1;
 	}
       /* PR 17531: file: 639d6a26.  */
-      if ((signed long) arch->longnames_size < 0)
+      if (arch->longnames_size > file_size
+	  || (signed long) arch->longnames_size < 0)
 	{
 	  error (_("%s: long name table is too big, (size = 0x%lx)\n"),
 		 file_name, arch->longnames_size);
@@ -713,6 +714,7 @@ setup_nested_archive (struct archive_info *nested_arch,
 		      const char *member_file_name)
 {
   FILE * member_file;
+  struct stat statbuf;
 
   /* Have we already setup this archive?  */
   if (nested_arch->file_name != NULL
@@ -727,8 +729,10 @@ setup_nested_archive (struct archive_info *nested_arch,
   member_file = fopen (member_file_name, "rb");
   if (member_file == NULL)
     return 1;
+  if (fstat (fileno (member_file), &statbuf) < 0)
+    return 1;
   return setup_archive (nested_arch, member_file_name, member_file,
-			FALSE, FALSE);
+			statbuf.st_size, FALSE, FALSE);
 }
 
 /* Release the memory used for the archive information.  */
diff --git a/binutils/elfcomm.h b/binutils/elfcomm.h
index 9bf3c41edbd..731d3dbd346 100644
--- a/binutils/elfcomm.h
+++ b/binutils/elfcomm.h
@@ -74,7 +74,7 @@ extern char *adjust_relative_path (const char *, const char *, unsigned long);
 
 /* Read the symbol table and long-name table from an archive.  */
 extern int setup_archive (struct archive_info *, const char *, FILE *,
-			  bfd_boolean, bfd_boolean);
+			  bfd_size_type, bfd_boolean, bfd_boolean);
 
 /* Open and setup a nested archive, if not already open.  */
 extern int setup_nested_archive (struct archive_info *, const char *);
diff --git a/binutils/elfedit.c b/binutils/elfedit.c
index 3a14c60ece6..d0e4e95f4d6 100644
--- a/binutils/elfedit.c
+++ b/binutils/elfedit.c
@@ -541,6 +541,7 @@ process_archive (const char * file_name, FILE * file,
   struct archive_info nested_arch;
   size_t got;
   int ret;
+  struct stat statbuf;
 
   /* The ARCH structure is used to hold information about this archive.  */
   arch.file_name = NULL;
@@ -558,7 +559,9 @@ process_archive (const char * file_name, FILE * file,
   nested_arch.sym_table = NULL;
   nested_arch.longnames = NULL;
 
-  if (setup_archive (&arch, file_name, file, is_thin_archive, FALSE) != 0)
+  if (fstat (fileno (file), &statbuf) < 0
+      || setup_archive (&arch, file_name, file, statbuf.st_size,
+			is_thin_archive, FALSE) != 0)
     {
       ret = 1;
       goto out;
diff --git a/binutils/readelf.c b/binutils/readelf.c
index b106e8c816f..0f8a0809c55 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -20247,7 +20247,8 @@ process_archive (Filedata * filedata, bfd_boolean is_thin_archive)
   nested_arch.longnames = NULL;
 
   if (setup_archive (&arch, filedata->file_name, filedata->handle,
-		     is_thin_archive, do_archive_index) != 0)
+		     filedata->file_size, is_thin_archive,
+		     do_archive_index) != 0)
     {
       ret = FALSE;
       goto out;


More information about the Binutils-cvs mailing list