PR26011, excessive memory allocation with fuzzed reloc sections
authorAlan Modra <amodra@gmail.com>
Tue, 19 May 2020 22:25:56 +0000 (07:55 +0930)
committerAlan Modra <amodra@gmail.com>
Tue, 19 May 2020 22:29:15 +0000 (07:59 +0930)
Check sizes early, before users of slurp_relocs allocate buffers for
the swapped in relocs.

PR 26011
* elf.c (_bfd_elf_get_reloc_upper_bound): Sanity check reloc
section size against file size.
(_bfd_elf_get_dynamic_reloc_upper_bound): Likewise.

bfd/ChangeLog
bfd/elf.c

index cb168f17684ef55ae2c784cb690ff56ba87de946..6d3673d14c156df81f4ad15c83ae2191cc5e0f5f 100644 (file)
@@ -1,3 +1,10 @@
+2020-05-20  Alan Modra  <amodra@gmail.com>
+
+       PR 26011
+       * elf.c (_bfd_elf_get_reloc_upper_bound): Sanity check reloc
+       section size against file size.
+       (_bfd_elf_get_dynamic_reloc_upper_bound): Likewise.
+
 2020-05-19  Gunther Nikl  <gnikl@justmail.de>
 
        PR 26005
index 40943781bcd8ba8c4cadb17b55398134bdbfbd78..0211970991c1d6d9ffe5ad3fbd8534acae9cd330 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -8508,9 +8508,23 @@ _bfd_elf_get_dynamic_symtab_upper_bound (bfd *abfd)
 }
 
 long
-_bfd_elf_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED,
-                               sec_ptr asect)
+_bfd_elf_get_reloc_upper_bound (bfd *abfd, sec_ptr asect)
 {
+  if (asect->reloc_count != 0)
+    {
+      /* Sanity check reloc section size.  */
+      struct bfd_elf_section_data *d = elf_section_data (asect);
+      Elf_Internal_Shdr *rel_hdr = &d->this_hdr;
+      bfd_size_type ext_rel_size = rel_hdr->sh_size;
+      ufile_ptr filesize = bfd_get_file_size (abfd);
+
+      if (filesize != 0 && ext_rel_size > filesize)
+       {
+         bfd_set_error (bfd_error_file_truncated);
+         return -1;
+       }
+    }
+
 #if SIZEOF_LONG == SIZEOF_INT
   if (asect->reloc_count >= LONG_MAX / sizeof (arelent *))
     {
@@ -8576,7 +8590,7 @@ _bfd_elf_canonicalize_dynamic_symtab (bfd *abfd,
 long
 _bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd)
 {
-  bfd_size_type count;
+  bfd_size_type count, ext_rel_size;
   asection *s;
 
   if (elf_dynsymtab (abfd) == 0)
@@ -8586,11 +8600,18 @@ _bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd)
     }
 
   count = 1;
+  ext_rel_size = 0;
   for (s = abfd->sections; s != NULL; s = s->next)
     if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
        && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
            || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
       {
+       ext_rel_size += s->size;
+       if (ext_rel_size < s->size)
+         {
+           bfd_set_error (bfd_error_file_truncated);
+           return -1;
+         }
        count += s->size / elf_section_data (s)->this_hdr.sh_entsize;
        if (count > LONG_MAX / sizeof (arelent *))
          {
@@ -8598,6 +8619,16 @@ _bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd)
            return -1;
          }
       }
+  if (count > 1)
+    {
+      /* Sanity check reloc section sizes.  */
+      ufile_ptr filesize = bfd_get_file_size (abfd);
+      if (filesize != 0 && ext_rel_size > filesize)
+       {
+         bfd_set_error (bfd_error_file_truncated);
+         return -1;
+       }
+    }
   return count * sizeof (arelent *);
 }