PR24336, buffer overflow in swap_reloca_in
[deliverable/binutils-gdb.git] / bfd / elflink.c
index 4eca389bd184a2e25dc0bef71bdcc2ef842134ef..2600c3934b12652741afca3cfafde61f09b57be3 100644 (file)
@@ -1,5 +1,5 @@
 /* ELF linking support for BFD.
-   Copyright (C) 1995-2018 Free Software Foundation, Inc.
+   Copyright (C) 1995-2019 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -20,7 +20,6 @@
 
 #include "sysdep.h"
 #include "bfd.h"
-#include "bfd_stdint.h"
 #include "bfdlink.h"
 #include "libbfd.h"
 #define ARCH_SIZE 0
@@ -1941,6 +1940,16 @@ _bfd_elf_add_default_symbol (bfd *abfd,
       if (! bfd_link_relocatable (info))
        {
          bh = &hi->root;
+         if (bh->type == bfd_link_hash_defined
+             && bh->u.def.section->owner != NULL
+             && (bh->u.def.section->owner->flags & BFD_PLUGIN) != 0)
+           {
+             /* Mark the previous definition from IR object as
+                undefined so that the generic linker will override
+                it.  */
+             bh->type = bfd_link_hash_undefined;
+             bh->u.undef.abfd = bh->u.def.section->owner;
+           }
          if (! (_bfd_generic_link_add_one_symbol
                 (info, abfd, shortname, BSF_INDIRECT,
                  bfd_ind_section_ptr,
@@ -2514,9 +2523,11 @@ elf_link_read_relocs_from_section (bfd *abfd,
     }
 
   erela = (const bfd_byte *) external_relocs;
-  erelaend = erela + shdr->sh_size;
+  /* Setting erelaend like this and comparing with <= handles case of
+     a fuzzed object with sh_size not a multiple of sh_entsize.  */
+  erelaend = erela + shdr->sh_size - shdr->sh_entsize;
   irela = internal_relocs;
-  while (erela < erelaend)
+  while (erela <= erelaend)
     {
       bfd_vma r_symndx;
 
@@ -3864,6 +3875,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
   struct elf_link_hash_entry **sym_hash;
   bfd_boolean dynamic;
   Elf_External_Versym *extversym = NULL;
+  Elf_External_Versym *extversym_end = NULL;
   Elf_External_Versym *ever;
   struct elf_link_hash_entry *weaks;
   struct elf_link_hash_entry **nondeflt_vers = NULL;
@@ -4178,7 +4190,7 @@ error_free_dyn:
         all sections contained fully therein.  This makes relro
         shared library sections appear as they will at run-time.  */
       phdr = elf_tdata (abfd)->phdr + elf_elfheader (abfd)->e_phnum;
-      while (--phdr >= elf_tdata (abfd)->phdr)
+      while (phdr-- > elf_tdata (abfd)->phdr)
        if (phdr->p_type == PT_GNU_RELRO)
          {
            for (s = abfd->sections; s != NULL; s = s->next)
@@ -4289,13 +4301,14 @@ error_free_dyn:
          Elf_Internal_Shdr *versymhdr;
 
          versymhdr = &elf_tdata (abfd)->dynversym_hdr;
-         extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
+         amt = versymhdr->sh_size;
+         extversym = (Elf_External_Versym *) bfd_malloc (amt);
          if (extversym == NULL)
            goto error_free_sym;
-         amt = versymhdr->sh_size;
          if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
              || bfd_bread (extversym, amt, abfd) != amt)
            goto error_free_vers;
+         extversym_end = extversym + (amt / sizeof (* extversym));
        }
     }
 
@@ -4370,7 +4383,20 @@ error_free_dyn:
     }
 
   weaks = NULL;
-  ever = extversym != NULL ? extversym + extsymoff : NULL;
+  if (extversym == NULL)
+    ever = NULL;
+  else if (extversym + extsymoff < extversym_end)
+    ever = extversym + extsymoff;
+  else
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: invalid version offset %lx (max %lx)"),
+                         abfd, (long) extsymoff,
+                         (long) (extversym_end - extversym) / sizeof (* extversym));
+      bfd_set_error (bfd_error_bad_value);
+      goto error_free_vers;
+    }
+
   for (isym = isymbuf, isymend = isymbuf + extsymcount;
        isym < isymend;
        isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
@@ -4554,6 +4580,14 @@ error_free_dyn:
              else
                iver.vs_vers = 0;
            }
+         else if (ever >= extversym_end)
+           {
+             /* xgettext:c-format */
+             _bfd_error_handler (_("%pB: not enough version information"),
+                                 abfd);
+             bfd_set_error (bfd_error_bad_value);
+             goto error_free_vers;
+           }
          else
            _bfd_elf_swap_versym_in (abfd, ever, &iver);
 
This page took 0.026442 seconds and 4 git commands to generate.