PR28402, fail to allocate line number array
authorAlan Modra <amodra@gmail.com>
Wed, 6 Oct 2021 03:08:42 +0000 (13:38 +1030)
committerAlan Modra <amodra@gmail.com>
Wed, 6 Oct 2021 05:00:23 +0000 (15:30 +1030)
This fixes a situation where the COFF code allocated memory for
internal representaion arrays before reading the external file data.
That meant the allocation didn't have any sanity check against file
size.

PR 28402
* coffcode.h (buy_and_read): Malloc rather than alloc memory.
(coff_slurp_line_table): Read native line number info before
allocating memory for internal line number array.  Adjust error
paths to suit.  Remove now unnecessary line number count check.
(coff_slurp_reloc_table): Adjust to suit buy_and_read change.

bfd/coffcode.h

index d5d9153c4c4ca77b0aacc52be39a49672badce61..c28d753011ab6c1d8e6aaf5aea18ab6bdf47c8aa 100644 (file)
@@ -4294,7 +4294,7 @@ buy_and_read (bfd *abfd, file_ptr where,
     }
   if (bfd_seek (abfd, where, SEEK_SET) != 0)
     return NULL;
-  return _bfd_alloc_and_read (abfd, amt, amt);
+  return _bfd_malloc_and_read (abfd, amt, amt);
 }
 
 /*
@@ -4358,31 +4358,26 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
 
   BFD_ASSERT (asect->lineno == NULL);
 
-  if (asect->lineno_count > asect->size)
+  native_lineno = (LINENO *) buy_and_read (abfd, asect->line_filepos,
+                                          asect->lineno_count,
+                                          bfd_coff_linesz (abfd));
+  if (native_lineno == NULL)
     {
       _bfd_error_handler
-       (_("%pB: warning: line number count (%#lx) exceeds section size (%#lx)"),
-        abfd, (unsigned long) asect->lineno_count, (unsigned long) asect->size);
+       (_("%pB: warning: line number table read failed"), abfd);
       return false;
     }
 
   if (_bfd_mul_overflow (asect->lineno_count + 1, sizeof (alent), &amt))
     {
       bfd_set_error (bfd_error_file_too_big);
+      free (native_lineno);
       return false;
     }
   lineno_cache = (alent *) bfd_alloc (abfd, amt);
   if (lineno_cache == NULL)
-    return false;
-
-  native_lineno = (LINENO *) buy_and_read (abfd, asect->line_filepos,
-                                          asect->lineno_count,
-                                          bfd_coff_linesz (abfd));
-  if (native_lineno == NULL)
     {
-      _bfd_error_handler
-       (_("%pB: warning: line number table read failed"), abfd);
-      bfd_release (abfd, lineno_cache);
+      free (native_lineno);
       return false;
     }
 
@@ -4475,7 +4470,7 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
 
   asect->lineno_count = cache_ptr - lineno_cache;
   memset (cache_ptr, 0, sizeof (*cache_ptr));
-  bfd_release (abfd, native_lineno);
+  free (native_lineno);
 
   /* On some systems (eg AIX5.3) the lineno table may not be sorted.  */
   if (!ordered)
@@ -5093,14 +5088,20 @@ coff_slurp_reloc_table (bfd * abfd, sec_ptr asect, asymbol ** symbols)
   native_relocs = (RELOC *) buy_and_read (abfd, asect->rel_filepos,
                                          asect->reloc_count,
                                          bfd_coff_relsz (abfd));
+  if (native_relocs == NULL)
+    return false;
+
   if (_bfd_mul_overflow (asect->reloc_count, sizeof (arelent), &amt))
     {
       bfd_set_error (bfd_error_file_too_big);
       return false;
     }
   reloc_cache = (arelent *) bfd_alloc (abfd, amt);
-  if (reloc_cache == NULL || native_relocs == NULL)
-    return false;
+  if (reloc_cache == NULL)
+    {
+      free (native_relocs);
+      return false;
+    }
 
   for (idx = 0; idx < asect->reloc_count; idx++)
     {
@@ -5170,10 +5171,12 @@ coff_slurp_reloc_table (bfd * abfd, sec_ptr asect, asymbol ** symbols)
            (_("%pB: illegal relocation type %d at address %#" PRIx64),
             abfd, dst.r_type, (uint64_t) dst.r_vaddr);
          bfd_set_error (bfd_error_bad_value);
+         free (native_relocs);
          return false;
        }
     }
 
+  free (native_relocs);
   asect->relocation = reloc_cache;
   return true;
 }