ELF core file size checks
authorAlan Modra <amodra@gmail.com>
Fri, 29 Oct 2021 04:39:52 +0000 (15:09 +1030)
committerAlan Modra <amodra@gmail.com>
Fri, 29 Oct 2021 06:52:32 +0000 (17:22 +1030)
Catch fuzzed segments where p_offset + p_filesz wraps, and limit error
output.

* elfcore.h (elf_core_file_p): Rewrite segment checks using
bfd_get_file_size.  Set read_only on file size errors.
* elfcode.h (elf_swap_shdr_in): Don't repeat error message.

bfd/elfcode.h
bfd/elfcore.h

index 7eb27c2e16dcba32da8e0b0396fdd25c7be313d6..ee88fce487d73a25c24234943ef08294f71c56bd 100644 (file)
@@ -325,9 +325,10 @@ elf_swap_shdr_in (bfd *abfd,
          && ((ufile_ptr) dst->sh_offset > filesize
              || dst->sh_size > filesize - dst->sh_offset))
        {
+         if (!abfd->read_only)
+           _bfd_error_handler (_("warning: %pB has a section "
+                                 "extending past end of file"), abfd);
          abfd->read_only = 1;
-         _bfd_error_handler (_("warning: %pB has a section "
-                               "extending past end of file"), abfd);
        }
     }
   dst->sh_link = H_GET_32 (abfd, src->sh_link);
index c0cdceba42a4f7d03514bebb210190b18ada2a74..832818f6cd19215a44c9297fb71feb0c357b7f48 100644 (file)
@@ -92,6 +92,7 @@ elf_core_file_p (bfd *abfd)
   unsigned int phindex;
   const struct elf_backend_data *ebd;
   bfd_size_type amt;
+  ufile_ptr filesize;
 
   /* Read in the ELF header in external format.  */
   if (bfd_bread (&x_ehdr, sizeof (x_ehdr), abfd) != sizeof (x_ehdr))
@@ -286,29 +287,21 @@ elf_core_file_p (bfd *abfd)
       goto fail;
 
   /* Check for core truncation.  */
-  {
-    bfd_size_type high = 0;
-    struct stat statbuf;
-    for (phindex = 0; phindex < i_ehdrp->e_phnum; ++phindex)
-      {
-       Elf_Internal_Phdr *p = i_phdrp + phindex;
-       if (p->p_filesz)
-         {
-           bfd_size_type current = p->p_offset + p->p_filesz;
-           if (high < current)
-             high = current;
-         }
-      }
-    if (bfd_stat (abfd, &statbuf) == 0)
-      {
-       if ((bfd_size_type) statbuf.st_size < high)
-         {
-           _bfd_error_handler
-             /* xgettext:c-format */
-             (_("warning: %pB is truncated: expected core file "
-                "size >= %" PRIu64 ", found: %" PRIu64),
-              abfd, (uint64_t) high, (uint64_t) statbuf.st_size);
-         }
+  filesize = bfd_get_file_size (abfd);
+  if (filesize != 0)
+    {
+      for (phindex = 0; phindex < i_ehdrp->e_phnum; ++phindex)
+       {
+         Elf_Internal_Phdr *p = i_phdrp + phindex;
+         if (p->p_filesz
+             && (p->p_offset >= filesize
+                 || p->p_filesz > filesize - p->p_offset))
+           {
+             _bfd_error_handler (_("warning: %pB has a segment "
+                                   "extending past end of file"), abfd);
+             abfd->read_only = 1;
+             break;
+           }
       }
   }