This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] bfd robustification (arithmetic overflows on allocation in elf.c and corrupt version section handling)


Hi!

This is another patch to somewhat robustify bfd.
It adds 5 new allocation functions that all take nmemb, size
arguments instead of a single size argument (similarly to calloc)
and check for overflow.  If you have ideas for better names,
please let me know.  So far I have just changed elf.c to use
them where appropriate.

Plus there were several problems when handling corrupt version definition
or version needed sections and crashes when seeing unknown relocation
types on several architectures.

2005-06-15  Jakub Jelinek  <jakub@redhat.com>

	* libbfd-in.h (bfd_malloc2, bfd_realloc2, bfd_zmalloc2, bfd_alloc2,
	bfd_zalloc2): New prototypes.
	* bfd-in.h (HALF_BFD_SIZE_TYPE): Define.
	* libbfd.c (bfd_malloc2, bfd_realloc2, bfd_zmalloc2): New functions.
	* opncls.c (bfd_alloc2, bfd_zalloc2): New functions.
	* elf.c (bfd_elf_get_elf_syms, setup_group, assign_section_numbers,
	elf_map_symbols, map_sections_to_segments,
	assign_file_positions_for_segments, copy_private_bfd_data,
	swap_out_syms, _bfd_elf_slurp_version_tables): Use bfd_*alloc2
	where appropriate.
	* bfd-in2.h: Rebuilt.
	* libbfd.h: Rebuilt.

	* elf.c (_bfd_elf_print_private_bfd_data): Don't crash on bogus
	verdef or verneed section.
	(_bfd_elf_slurp_version_tables): Handle corrupt verdef and/or
	verneed sections gracefully.
	* elfxx-sparc.c (_bfd_sparc_elf_info_to_howto_ptr): Don't crash on
	bogus relocation values.
	* elf64-ppc.c (ppc64_elf_info_to_howto): Likewise.
	* elf64-s390.c (elf_s390_info_to_howto): Likewise.
	* elf32-s390.c (elf_s390_info_to_howto): Likewise.
	* elf64-x86-64.c (elf64_x86_64_info_to_howto): Likewise.
	* elfxx-ia64.c (lookup_howto): Likewise.

--- bfd/libbfd-in.h.jj	2005-06-09 10:58:51.000000000 +0200
+++ bfd/libbfd-in.h	2005-06-15 18:17:24.000000000 +0200
@@ -93,6 +93,12 @@ extern void *bfd_realloc
   (void *, bfd_size_type);
 extern void *bfd_zmalloc
   (bfd_size_type);
+extern void *bfd_malloc2
+  (bfd_size_type, bfd_size_type);
+extern void *bfd_realloc2
+  (void *, bfd_size_type, bfd_size_type);
+extern void *bfd_zmalloc2
+  (bfd_size_type, bfd_size_type);
 
 extern void _bfd_default_error_handler (const char *s, ...);
 extern bfd_error_handler_type _bfd_error_handler;
@@ -103,6 +109,10 @@ extern void *bfd_alloc
   (bfd *, bfd_size_type);
 extern void *bfd_zalloc
   (bfd *, bfd_size_type);
+extern void *bfd_alloc2
+  (bfd *, bfd_size_type, bfd_size_type);
+extern void *bfd_zalloc2
+  (bfd *, bfd_size_type, bfd_size_type);
 extern void bfd_release
   (bfd *, void *);
 
--- bfd/bfd-in.h.jj	2005-05-13 23:44:03.000000000 +0200
+++ bfd/bfd-in.h	2005-06-15 18:09:32.000000000 +0200
@@ -136,6 +136,9 @@ typedef unsigned long bfd_size_type;
 
 #endif /* not BFD64  */
 
+#define HALF_BFD_SIZE_TYPE \
+  (((bfd_size_type) 1) << (8 * sizeof (bfd_size_type) / 2))
+
 #ifndef BFD_HOST_64_BIT
 /* Fall back on a 32 bit type.  The idea is to make these types always
    available for function return types, but in the case that
--- bfd/libbfd.c.jj	2005-06-09 10:58:51.000000000 +0200
+++ bfd/libbfd.c	2005-06-15 18:16:06.000000000 +0200
@@ -156,6 +156,36 @@ bfd_malloc (bfd_size_type size)
   return ptr;
 }
 
+/* Allocate memory using malloc, nmemb * size with overflow checking.  */
+
+void *
+bfd_malloc2 (bfd_size_type nmemb, bfd_size_type size)
+{
+  void *ptr;
+
+  if ((nmemb | size) >= HALF_BFD_SIZE_TYPE
+      && size != 0
+      && nmemb > ~(bfd_size_type) 0 / size)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
+    }
+
+  size *= nmemb;
+
+  if (size != (size_t) size)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
+    }
+
+  ptr = malloc ((size_t) size);
+  if (ptr == NULL && (size_t) size != 0)
+    bfd_set_error (bfd_error_no_memory);
+
+  return ptr;
+}
+
 /* Reallocate memory using realloc.  */
 
 void *
@@ -180,6 +210,40 @@ bfd_realloc (void *ptr, bfd_size_type si
   return ret;
 }
 
+/* Reallocate memory using realloc, nmemb * size with overflow checking.  */
+
+void *
+bfd_realloc2 (void *ptr, bfd_size_type nmemb, bfd_size_type size)
+{
+  void *ret;
+
+  if ((nmemb | size) >= HALF_BFD_SIZE_TYPE
+      && size != 0
+      && nmemb > ~(bfd_size_type) 0 / size)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
+    }
+
+  size *= nmemb;
+
+  if (size != (size_t) size)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
+    }
+
+  if (ptr == NULL)
+    ret = malloc ((size_t) size);
+  else
+    ret = realloc (ptr, (size_t) size);
+
+  if (ret == NULL && (size_t) size != 0)
+    bfd_set_error (bfd_error_no_memory);
+
+  return ret;
+}
+
 /* Allocate memory using malloc and clear it.  */
 
 void *
@@ -205,6 +269,44 @@ bfd_zmalloc (bfd_size_type size)
 
   return ptr;
 }
+
+/* Allocate memory using malloc (nmemb * size) with overflow checking
+   and clear it.  */
+
+void *
+bfd_zmalloc2 (bfd_size_type nmemb, bfd_size_type size)
+{
+  void *ptr;
+
+  if ((nmemb | size) >= HALF_BFD_SIZE_TYPE
+      && size != 0
+      && nmemb > ~(bfd_size_type) 0 / size)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
+    }
+
+  size *= nmemb;
+
+  if (size != (size_t) size)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
+    }
+
+  ptr = malloc ((size_t) size);
+
+  if ((size_t) size != 0)
+    {
+      if (ptr == NULL)
+	bfd_set_error (bfd_error_no_memory);
+      else
+	memset (ptr, 0, (size_t) size);
+    }
+
+  return ptr;
+}
+
 /*
 INTERNAL_FUNCTION
 	bfd_write_bigendian_4byte_int
--- bfd/opncls.c.jj	2005-06-09 10:58:51.000000000 +0200
+++ bfd/opncls.c	2005-06-15 19:13:42.000000000 +0200
@@ -858,6 +858,45 @@ bfd_alloc (bfd *abfd, bfd_size_type size
 
 /*
 INTERNAL_FUNCTION
+	bfd_alloc2
+
+SYNOPSIS
+	void *bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size);
+
+DESCRIPTION
+	Allocate a block of @var{nmemb} elements of @var{size} bytes each
+	of memory attached to <<abfd>> and return a pointer to it.
+*/
+
+void *
+bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size)
+{
+  void *ret;
+
+  if ((nmemb | size) >= HALF_BFD_SIZE_TYPE
+      && size != 0
+      && nmemb > ~(bfd_size_type) 0 / size)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
+    }
+
+  size *= nmemb;
+
+  if (size != (unsigned long) size)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
+    }
+
+  ret = objalloc_alloc (abfd->memory, (unsigned long) size);
+  if (ret == NULL)
+    bfd_set_error (bfd_error_no_memory);
+  return ret;
+}
+
+/*
+INTERNAL_FUNCTION
 	bfd_zalloc
 
 SYNOPSIS
@@ -879,6 +918,39 @@ bfd_zalloc (bfd *abfd, bfd_size_type siz
   return res;
 }
 
+/*
+INTERNAL_FUNCTION
+	bfd_zalloc2
+
+SYNOPSIS
+	void *bfd_zalloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size);
+
+DESCRIPTION
+	Allocate a block of @var{nmemb} elements of @var{size} bytes each
+	of zeroed memory attached to <<abfd>> and return a pointer to it.
+*/
+
+void *
+bfd_zalloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size)
+{
+  void *res;
+
+  if ((nmemb | size) >= HALF_BFD_SIZE_TYPE
+      && size != 0
+      && nmemb > ~(bfd_size_type) 0 / size)
+    {
+      bfd_set_error (bfd_error_no_memory);
+      return NULL;
+    }
+
+  size *= nmemb;
+
+  res = bfd_alloc (abfd, size);
+  if (res)
+    memset (res, 0, (size_t) size);
+  return res;
+}
+
 /* Free a block allocated for a BFD.
    Note:  Also frees all more recently allocated blocks!  */
 
--- bfd/elf.c.jj	2005-06-15 17:52:18.000000000 +0200
+++ bfd/elf.c	2005-06-15 22:52:28.000000000 +0200
@@ -340,7 +340,7 @@ bfd_elf_get_elf_syms (bfd *ibfd,
   pos = symtab_hdr->sh_offset + symoffset * extsym_size;
   if (extsym_buf == NULL)
     {
-      alloc_ext = bfd_malloc (amt);
+      alloc_ext = bfd_malloc2 (symcount, extsym_size);
       extsym_buf = alloc_ext;
     }
   if (extsym_buf == NULL
@@ -359,7 +359,8 @@ bfd_elf_get_elf_syms (bfd *ibfd,
       pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx);
       if (extshndx_buf == NULL)
 	{
-	  alloc_extshndx = bfd_malloc (amt);
+	  alloc_extshndx = bfd_malloc2 (symcount,
+					sizeof (Elf_External_Sym_Shndx));
 	  extshndx_buf = alloc_extshndx;
 	}
       if (extshndx_buf == NULL
@@ -373,8 +374,7 @@ bfd_elf_get_elf_syms (bfd *ibfd,
 
   if (intsym_buf == NULL)
     {
-      bfd_size_type amt = symcount * sizeof (Elf_Internal_Sym);
-      intsym_buf = bfd_malloc (amt);
+      intsym_buf = bfd_malloc2 (symcount, sizeof (Elf_Internal_Sym));
       if (intsym_buf == NULL)
 	goto out;
     }
@@ -494,10 +494,10 @@ setup_group (bfd *abfd, Elf_Internal_Shd
 	  /* We keep a list of elf section headers for group sections,
 	     so we can find them quickly.  */
 	  bfd_size_type amt;
-	  
+
 	  elf_tdata (abfd)->num_group = num_group;
-	  amt = num_group * sizeof (Elf_Internal_Shdr *);
-	  elf_tdata (abfd)->group_sect_ptr = bfd_alloc (abfd, amt);
+	  elf_tdata (abfd)->group_sect_ptr
+	    = bfd_alloc2 (abfd, num_group, sizeof (Elf_Internal_Shdr *));
 	  if (elf_tdata (abfd)->group_sect_ptr == NULL)
 	    return FALSE;
 
@@ -517,7 +517,8 @@ setup_group (bfd *abfd, Elf_Internal_Shd
 		  /* Read the raw contents.  */
 		  BFD_ASSERT (sizeof (*dest) >= 4);
 		  amt = shdr->sh_size * sizeof (*dest) / 4;
-		  shdr->contents = bfd_alloc (abfd, amt);
+		  shdr->contents = bfd_alloc2 (abfd, shdr->sh_size,
+					       sizeof (*dest) / 4);
 		  if (shdr->contents == NULL
 		      || bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0
 		      || (bfd_bread (shdr->contents, shdr->sh_size, abfd)
@@ -1219,8 +1220,9 @@ _bfd_elf_print_private_bfd_data (bfd *ab
       for (t = elf_tdata (abfd)->verdef; t != NULL; t = t->vd_nextdef)
 	{
 	  fprintf (f, "%d 0x%2.2x 0x%8.8lx %s\n", t->vd_ndx,
-		   t->vd_flags, t->vd_hash, t->vd_nodename);
-	  if (t->vd_auxptr->vda_nextptr != NULL)
+		   t->vd_flags, t->vd_hash,
+		   t->vd_nodename ? t->vd_nodename : "<corrupt>");
+	  if (t->vd_auxptr != NULL && t->vd_auxptr->vda_nextptr != NULL)
 	    {
 	      Elf_Internal_Verdaux *a;
 
@@ -1228,7 +1230,8 @@ _bfd_elf_print_private_bfd_data (bfd *ab
 	      for (a = t->vd_auxptr->vda_nextptr;
 		   a != NULL;
 		   a = a->vda_nextptr)
-		fprintf (f, "%s ", a->vda_nodename);
+		fprintf (f, "%s ",
+			 a->vda_nodename ? a->vda_nodename : "<corrupt>");
 	      fprintf (f, "\n");
 	    }
 	}
@@ -1243,10 +1246,12 @@ _bfd_elf_print_private_bfd_data (bfd *ab
 	{
 	  Elf_Internal_Vernaux *a;
 
-	  fprintf (f, _("  required from %s:\n"), t->vn_filename);
+	  fprintf (f, _("  required from %s:\n"),
+		   t->vn_filename ? t->vn_filename : "<corrupt>");
 	  for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
 	    fprintf (f, "    0x%8.8lx 0x%2.2x %2.2d %s\n", a->vna_hash,
-		     a->vna_flags, a->vna_other, a->vna_nodename);
+		     a->vna_flags, a->vna_other,
+		     a->vna_nodename ? a->vna_nodename : "<corrupt>");
 	}
     }
 
@@ -2899,7 +2904,6 @@ assign_section_numbers (bfd *abfd, struc
   asection *sec;
   unsigned int section_number, secn;
   Elf_Internal_Shdr **i_shdrp;
-  bfd_size_type amt;
   struct bfd_elf_section_data *d;
 
   section_number = 1;
@@ -3003,13 +3007,11 @@ assign_section_numbers (bfd *abfd, struc
 
   /* Set up the list of section header pointers, in agreement with the
      indices.  */
-  amt = section_number * sizeof (Elf_Internal_Shdr *);
-  i_shdrp = bfd_zalloc (abfd, amt);
+  i_shdrp = bfd_zalloc2 (abfd, section_number, sizeof (Elf_Internal_Shdr *));
   if (i_shdrp == NULL)
     return FALSE;
 
-  amt = sizeof (Elf_Internal_Shdr);
-  i_shdrp[0] = bfd_zalloc (abfd, amt);
+  i_shdrp[0] = bfd_zalloc (abfd, sizeof (Elf_Internal_Shdr));
   if (i_shdrp[0] == NULL)
     {
       bfd_release (abfd, i_shdrp);
@@ -3260,7 +3262,6 @@ elf_map_symbols (bfd *abfd)
   unsigned int idx;
   asection *asect;
   asymbol **new_syms;
-  bfd_size_type amt;
 
 #ifdef DEBUG
   fprintf (stderr, "elf_map_symbols\n");
@@ -3274,8 +3275,7 @@ elf_map_symbols (bfd *abfd)
     }
 
   max_index++;
-  amt = max_index * sizeof (asymbol *);
-  sect_syms = bfd_zalloc (abfd, amt);
+  sect_syms = bfd_zalloc2 (abfd, max_index, sizeof (asymbol *));
   if (sect_syms == NULL)
     return FALSE;
   elf_section_syms (abfd) = sect_syms;
@@ -3348,8 +3348,7 @@ elf_map_symbols (bfd *abfd)
     }
 
   /* Now sort the symbols so the local symbols are first.  */
-  amt = (num_locals + num_globals) * sizeof (asymbol *);
-  new_syms = bfd_alloc (abfd, amt);
+  new_syms = bfd_alloc2 (abfd, num_locals + num_globals, sizeof (asymbol *));
 
   if (new_syms == NULL)
     return FALSE;
@@ -3608,8 +3607,7 @@ map_sections_to_segments (bfd *abfd)
 
   /* Select the allocated sections, and sort them.  */
 
-  amt = bfd_count_sections (abfd) * sizeof (asection *);
-  sections = bfd_malloc (amt);
+  sections = bfd_malloc2 (bfd_count_sections (abfd), sizeof (asection *));
   if (sections == NULL)
     goto error_return;
 
@@ -4041,7 +4039,6 @@ assign_file_positions_for_segments (bfd 
   bfd_vma filehdr_vaddr, filehdr_paddr;
   bfd_vma phdrs_vaddr, phdrs_paddr;
   Elf_Internal_Phdr *p;
-  bfd_size_type amt;
 
   if (elf_tdata (abfd)->segment_map == NULL)
     {
@@ -4116,8 +4113,7 @@ assign_file_positions_for_segments (bfd 
   if (alloc == 0)
     alloc = count;
 
-  amt = alloc * sizeof (Elf_Internal_Phdr);
-  phdrs = bfd_alloc (abfd, amt);
+  phdrs = bfd_alloc2 (abfd, alloc, sizeof (Elf_Internal_Phdr));
   if (phdrs == NULL)
     return FALSE;
 
@@ -5377,8 +5373,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *o
 
       /* Gcc 2.96 miscompiles this code on mips. Don't do casting here
 	 to work around this long long bug.  */
-      amt = section_count * sizeof (asection *);
-      sections = bfd_malloc (amt);
+      sections = bfd_malloc2 (section_count, sizeof (asection *));
       if (sections == NULL)
 	return FALSE;
 
@@ -5800,8 +5795,7 @@ swap_out_syms (bfd *abfd,
   symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
   symstrtab_hdr->sh_type = SHT_STRTAB;
 
-  amt = (bfd_size_type) (1 + symcount) * bed->s->sizeof_sym;
-  outbound_syms = bfd_alloc (abfd, amt);
+  outbound_syms = bfd_alloc2 (abfd, 1 + symcount, bed->s->sizeof_sym);
   if (outbound_syms == NULL)
     {
       _bfd_stringtab_free (stt);
@@ -5814,7 +5808,8 @@ swap_out_syms (bfd *abfd,
   if (symtab_shndx_hdr->sh_name != 0)
     {
       amt = (bfd_size_type) (1 + symcount) * sizeof (Elf_External_Sym_Shndx);
-      outbound_shndx = bfd_zalloc (abfd, amt);
+      outbound_shndx = bfd_zalloc2 (abfd, 1 + symcount,
+				    sizeof (Elf_External_Sym_Shndx));
       if (outbound_shndx == NULL)
 	{
 	  _bfd_stringtab_free (stt);
@@ -6227,7 +6222,6 @@ bfd_boolean
 _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver)
 {
   bfd_byte *contents = NULL;
-  bfd_size_type amt;
   unsigned int freeidx = 0;
 
   if (elf_dynverref (abfd) != 0)
@@ -6236,11 +6230,12 @@ _bfd_elf_slurp_version_tables (bfd *abfd
       Elf_External_Verneed *everneed;
       Elf_Internal_Verneed *iverneed;
       unsigned int i;
+      bfd_byte *contents_end;
 
       hdr = &elf_tdata (abfd)->dynverref_hdr;
 
-      amt = (bfd_size_type) hdr->sh_info * sizeof (Elf_Internal_Verneed);
-      elf_tdata (abfd)->verref = bfd_zalloc (abfd, amt);
+      elf_tdata (abfd)->verref = bfd_zalloc2 (abfd, hdr->sh_info,
+					      sizeof (Elf_Internal_Verneed));
       if (elf_tdata (abfd)->verref == NULL)
 	goto error_return;
 
@@ -6248,11 +6243,22 @@ _bfd_elf_slurp_version_tables (bfd *abfd
 
       contents = bfd_malloc (hdr->sh_size);
       if (contents == NULL)
-	goto error_return;
+	{
+error_return_verref:
+	  elf_tdata (abfd)->verref = NULL;
+	  elf_tdata (abfd)->cverrefs = 0;
+	  goto error_return;
+	}
       if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
 	  || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
-	goto error_return;
+	goto error_return_verref;
 
+      if (hdr->sh_info && hdr->sh_size < sizeof (Elf_External_Verneed))
+	goto error_return_verref;
+
+      BFD_ASSERT (sizeof (Elf_External_Verneed)
+		  == sizeof (Elf_External_Vernaux));
+      contents_end = contents + hdr->sh_size - sizeof (Elf_External_Verneed);
       everneed = (Elf_External_Verneed *) contents;
       iverneed = elf_tdata (abfd)->verref;
       for (i = 0; i < hdr->sh_info; i++, iverneed++)
@@ -6269,11 +6275,21 @@ _bfd_elf_slurp_version_tables (bfd *abfd
 	    bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
 					     iverneed->vn_file);
 	  if (iverneed->vn_filename == NULL)
-	    goto error_return;
+	    goto error_return_verref;
 
-	  amt = iverneed->vn_cnt;
-	  amt *= sizeof (Elf_Internal_Vernaux);
-	  iverneed->vn_auxptr = bfd_alloc (abfd, amt);
+	  if (iverneed->vn_cnt == 0)
+	    iverneed->vn_auxptr = NULL;
+	  else
+	    {
+	      iverneed->vn_auxptr = bfd_alloc2 (abfd, iverneed->vn_cnt,
+						sizeof (Elf_Internal_Vernaux));
+	      if (iverneed->vn_auxptr == NULL)
+		goto error_return_verref;
+	    }
+
+	  if (iverneed->vn_aux
+	      > (size_t) (contents_end - (bfd_byte *) everneed))
+	    goto error_return_verref;
 
 	  evernaux = ((Elf_External_Vernaux *)
 		      ((bfd_byte *) everneed + iverneed->vn_aux));
@@ -6286,13 +6302,17 @@ _bfd_elf_slurp_version_tables (bfd *abfd
 		bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
 						 ivernaux->vna_name);
 	      if (ivernaux->vna_nodename == NULL)
-		goto error_return;
+		goto error_return_verref;
 
 	      if (j + 1 < iverneed->vn_cnt)
 		ivernaux->vna_nextptr = ivernaux + 1;
 	      else
 		ivernaux->vna_nextptr = NULL;
 
+	      if (ivernaux->vna_next
+		  > (size_t) (contents_end - (bfd_byte *) evernaux))
+		goto error_return_verref;
+
 	      evernaux = ((Elf_External_Vernaux *)
 			  ((bfd_byte *) evernaux + ivernaux->vna_next));
 
@@ -6305,6 +6325,10 @@ _bfd_elf_slurp_version_tables (bfd *abfd
 	  else
 	    iverneed->vn_nextref = NULL;
 
+	  if (iverneed->vn_next
+	      > (size_t) (contents_end - (bfd_byte *) everneed))
+	    goto error_return_verref;
+
 	  everneed = ((Elf_External_Verneed *)
 		      ((bfd_byte *) everneed + iverneed->vn_next));
 	}
@@ -6322,6 +6346,7 @@ _bfd_elf_slurp_version_tables (bfd *abfd
       Elf_Internal_Verdef iverdefmem;
       unsigned int i;
       unsigned int maxidx;
+      bfd_byte *contents_end_def, *contents_end_aux;
 
       hdr = &elf_tdata (abfd)->dynverdef_hdr;
 
@@ -6332,6 +6357,16 @@ _bfd_elf_slurp_version_tables (bfd *abfd
 	  || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
 	goto error_return;
 
+      if (hdr->sh_info && hdr->sh_size < sizeof (Elf_External_Verdef))
+	goto error_return;
+
+      BFD_ASSERT (sizeof (Elf_External_Verdef)
+		  >= sizeof (Elf_External_Verdaux));
+      contents_end_def = contents + hdr->sh_size
+			 - sizeof (Elf_External_Verdef);
+      contents_end_aux = contents + hdr->sh_size
+			 - sizeof (Elf_External_Verdaux);
+
       /* We know the number of entries in the section but not the maximum
 	 index.  Therefore we have to run through all entries and find
 	 the maximum.  */
@@ -6344,6 +6379,10 @@ _bfd_elf_slurp_version_tables (bfd *abfd
 	  if ((iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION)) > maxidx)
 	    maxidx = iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION);
 
+	  if (iverdefmem.vd_next
+	      > (size_t) (contents_end_def - (bfd_byte *) everdef))
+	    goto error_return;
+
 	  everdef = ((Elf_External_Verdef *)
 		     ((bfd_byte *) everdef + iverdefmem.vd_next));
 	}
@@ -6355,8 +6394,8 @@ _bfd_elf_slurp_version_tables (bfd *abfd
 	  else
 	    freeidx = ++maxidx;
 	}
-      amt = (bfd_size_type) maxidx * sizeof (Elf_Internal_Verdef);
-      elf_tdata (abfd)->verdef = bfd_zalloc (abfd, amt);
+      elf_tdata (abfd)->verdef = bfd_zalloc2 (abfd, maxidx,
+					      sizeof (Elf_Internal_Verdef));
       if (elf_tdata (abfd)->verdef == NULL)
 	goto error_return;
 
@@ -6372,15 +6411,32 @@ _bfd_elf_slurp_version_tables (bfd *abfd
 
 	  _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem);
 
+	  if ((iverdefmem.vd_ndx & VERSYM_VERSION) == 0)
+	    {
+error_return_verdef:
+	      elf_tdata (abfd)->verdef = NULL;
+	      elf_tdata (abfd)->cverdefs = 0;
+	      goto error_return;
+	    }
+
 	  iverdef = &iverdefarr[(iverdefmem.vd_ndx & VERSYM_VERSION) - 1];
 	  memcpy (iverdef, &iverdefmem, sizeof (Elf_Internal_Verdef));
 
 	  iverdef->vd_bfd = abfd;
 
-	  amt = (bfd_size_type) iverdef->vd_cnt * sizeof (Elf_Internal_Verdaux);
-	  iverdef->vd_auxptr = bfd_alloc (abfd, amt);
-	  if (iverdef->vd_auxptr == NULL)
-	    goto error_return;
+	  if (iverdef->vd_cnt == 0)
+	    iverdef->vd_auxptr = NULL;
+	  else
+	    {
+	      iverdef->vd_auxptr = bfd_alloc2 (abfd, iverdef->vd_cnt,
+					       sizeof (Elf_Internal_Verdaux));
+	      if (iverdef->vd_auxptr == NULL)
+		goto error_return_verdef;
+	    }
+
+	  if (iverdef->vd_aux
+	      > (size_t) (contents_end_aux - (bfd_byte *) everdef))
+	    goto error_return_verdef;
 
 	  everdaux = ((Elf_External_Verdaux *)
 		      ((bfd_byte *) everdef + iverdef->vd_aux));
@@ -6393,20 +6449,25 @@ _bfd_elf_slurp_version_tables (bfd *abfd
 		bfd_elf_string_from_elf_section (abfd, hdr->sh_link,
 						 iverdaux->vda_name);
 	      if (iverdaux->vda_nodename == NULL)
-		goto error_return;
+		goto error_return_verdef;
 
 	      if (j + 1 < iverdef->vd_cnt)
 		iverdaux->vda_nextptr = iverdaux + 1;
 	      else
 		iverdaux->vda_nextptr = NULL;
 
+	      if (iverdaux->vda_next
+		  > (size_t) (contents_end_aux - (bfd_byte *) everdaux))
+		goto error_return_verdef;
+
 	      everdaux = ((Elf_External_Verdaux *)
 			  ((bfd_byte *) everdaux + iverdaux->vda_next));
 	    }
 
-	  iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename;
+	  if (iverdef->vd_cnt)
+	    iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename;
 
-	  if (i + 1 < hdr->sh_info)
+	  if ((size_t) (iverdef - iverdefarr) + 1 < maxidx)
 	    iverdef->vd_nextdef = iverdef + 1;
 	  else
 	    iverdef->vd_nextdef = NULL;
@@ -6425,8 +6486,8 @@ _bfd_elf_slurp_version_tables (bfd *abfd
       else
 	freeidx++;
 
-      amt = (bfd_size_type) freeidx * sizeof (Elf_Internal_Verdef);
-      elf_tdata (abfd)->verdef = bfd_zalloc (abfd, amt);
+      elf_tdata (abfd)->verdef = bfd_zalloc2 (abfd, freeidx,
+					      sizeof (Elf_Internal_Verdef));
       if (elf_tdata (abfd)->verdef == NULL)
 	goto error_return;
 
@@ -6450,10 +6511,11 @@ _bfd_elf_slurp_version_tables (bfd *abfd
 
       iverdef->vd_nodename = bfd_elf_get_dt_soname (abfd);
       if (iverdef->vd_nodename == NULL)
-	goto error_return;
+	goto error_return_verdef;
       iverdef->vd_nextdef = NULL;
-      amt = (bfd_size_type) sizeof (Elf_Internal_Verdaux);
-      iverdef->vd_auxptr = bfd_alloc (abfd, amt);
+      iverdef->vd_auxptr = bfd_alloc (abfd, sizeof (Elf_Internal_Verdaux));
+      if (iverdef->vd_auxptr == NULL)
+	goto error_return_verdef;
 
       iverdaux = iverdef->vd_auxptr;
       iverdaux->vda_nodename = iverdef->vd_nodename;
--- bfd/elfxx-sparc.c.jj	2005-05-13 23:44:17.000000000 +0200
+++ bfd/elfxx-sparc.c	2005-06-15 23:11:53.000000000 +0200
@@ -397,7 +397,12 @@ _bfd_sparc_elf_info_to_howto_ptr (unsign
       return &sparc_rev32_howto;
 
     default:
-      BFD_ASSERT (r_type < (unsigned int) R_SPARC_max_std);
+      if (r_type >= (unsigned int) R_SPARC_max_std)
+	{
+	  (*_bfd_error_handler) (_("invalid relocation type %d"),
+				 (int) r_type);
+	  r_type = R_SPARC_NONE;
+	}
       return &_bfd_sparc_elf_howto_table[r_type];
     }
 }
--- bfd/elf64-ppc.c.jj	2005-06-09 10:58:51.000000000 +0200
+++ bfd/elf64-ppc.c	2005-06-15 23:01:46.000000000 +0200
@@ -2117,8 +2117,13 @@ ppc64_elf_info_to_howto (bfd *abfd ATTRI
     ppc_howto_init ();
 
   type = ELF64_R_TYPE (dst->r_info);
-  BFD_ASSERT (type < (sizeof (ppc64_elf_howto_table)
-		      / sizeof (ppc64_elf_howto_table[0])));
+  if (type >= (sizeof (ppc64_elf_howto_table)
+	       / sizeof (ppc64_elf_howto_table[0])))
+    {
+      (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
+			     abfd, (int) r_type);
+      r_type = R_PPC64_NONE;
+    }
   cache_ptr->howto = ppc64_elf_howto_table[type];
 }
 
--- bfd/elf64-s390.c.jj	2005-05-13 23:44:16.000000000 +0200
+++ bfd/elf64-s390.c	2005-06-15 23:06:36.000000000 +0200
@@ -373,7 +373,8 @@ elf_s390_info_to_howto (abfd, cache_ptr,
      arelent *cache_ptr;
      Elf_Internal_Rela *dst;
 {
-  switch (ELF64_R_TYPE(dst->r_info))
+  unsigned int r_type = ELF64_R_TYPE(dst->r_info);
+  switch (r_type)
     {
     case R_390_GNU_VTINHERIT:
       cache_ptr->howto = &elf64_s390_vtinherit_howto;
@@ -384,8 +385,13 @@ elf_s390_info_to_howto (abfd, cache_ptr,
       break;
 
     default:
-      BFD_ASSERT (ELF64_R_TYPE(dst->r_info) < (unsigned int) R_390_max);
-      cache_ptr->howto = &elf_howto_table[ELF64_R_TYPE(dst->r_info)];
+      if (r_type >= sizeof (elf_howto_table) / sizeof (elf_howto_table[0]))
+	{
+	  (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
+				 abfd, (int) r_type);
+	  r_type = R_390_NONE;
+	}
+      cache_ptr->howto = &elf_howto_table[r_type];
     }
 }
 
--- bfd/elf32-s390.c.jj	2005-05-13 23:44:13.000000000 +0200
+++ bfd/elf32-s390.c	2005-06-15 23:07:25.000000000 +0200
@@ -351,7 +351,8 @@ elf_s390_info_to_howto (abfd, cache_ptr,
      arelent *cache_ptr;
      Elf_Internal_Rela *dst;
 {
-  switch (ELF32_R_TYPE(dst->r_info))
+  unsigned int r_type = ELF32_R_TYPE(dst->r_info);
+  switch (r_type)
     {
     case R_390_GNU_VTINHERIT:
       cache_ptr->howto = &elf32_s390_vtinherit_howto;
@@ -362,8 +363,13 @@ elf_s390_info_to_howto (abfd, cache_ptr,
       break;
 
     default:
-      BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_390_max);
-      cache_ptr->howto = &elf_howto_table[ELF32_R_TYPE(dst->r_info)];
+      if (r_type >= sizeof (elf_howto_table) / sizeof (elf_howto_table[0]))
+	{
+	  (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
+				 abfd, (int) r_type);
+	  r_type = R_390_NONE;
+	}
+      cache_ptr->howto = &elf_howto_table[r_type];
     }
 }
 
--- bfd/elf64-x86-64.c.jj	2005-05-19 17:13:38.000000000 +0200
+++ bfd/elf64-x86-64.c	2005-06-15 21:24:22.000000000 +0200
@@ -177,16 +177,19 @@ elf64_x86_64_info_to_howto (bfd *abfd AT
   unsigned r_type, i;
 
   r_type = ELF64_R_TYPE (dst->r_info);
-  if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT)
+  if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT
+      || r_type >= (unsigned int) R_X86_64_max)
     {
-      BFD_ASSERT (r_type <= (unsigned int) R_X86_64_TPOFF32);
+      if (r_type > (unsigned int) R_X86_64_TPOFF32)
+	{
+	  (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
+				 abfd, (int) r_type);
+	  r_type = R_X86_64_NONE;
+	}
       i = r_type;
     }
   else
-    {
-      BFD_ASSERT (r_type < (unsigned int) R_X86_64_max);
-      i = r_type - ((unsigned int) R_X86_64_GNU_VTINHERIT - R_X86_64_TPOFF32 - 1);
-    }
+    i = r_type - ((unsigned int) R_X86_64_GNU_VTINHERIT - R_X86_64_TPOFF32 - 1);
   cache_ptr->howto = &x86_64_elf_howto_table[i];
   BFD_ASSERT (r_type == cache_ptr->howto->type);
 }
--- bfd/elfxx-ia64.c.jj	2005-05-19 17:13:38.000000000 +0200
+++ bfd/elfxx-ia64.c	2005-06-15 23:09:24.000000000 +0200
@@ -487,7 +487,8 @@ lookup_howto (rtype)
 	elf_code_to_howto_index[ia64_howto_table[i].type] = i;
     }
 
-  BFD_ASSERT (rtype <= R_IA64_MAX_RELOC_CODE);
+  if (rtype > R_IA64_MAX_RELOC_CODE)
+    return 0;
   i = elf_code_to_howto_index[rtype];
   if (i >= NELEMS (ia64_howto_table))
     return 0;
--- bfd/bfd-in2.h.jj	2005-06-09 10:58:49.000000000 +0200
+++ bfd/bfd-in2.h	2005-06-15 18:10:10.000000000 +0200
@@ -143,6 +143,9 @@ typedef unsigned long bfd_size_type;
 
 #endif /* not BFD64  */
 
+#define HALF_BFD_SIZE_TYPE \
+  (((bfd_size_type) 1) << (8 * sizeof (bfd_size_type) / 2))
+
 #ifndef BFD_HOST_64_BIT
 /* Fall back on a 32 bit type.  The idea is to make these types always
    available for function return types, but in the case that
--- bfd/libbfd.h.jj	2005-06-09 10:58:51.000000000 +0200
+++ bfd/libbfd.h	2005-06-15 18:18:52.000000000 +0200
@@ -98,6 +98,12 @@ extern void *bfd_realloc
   (void *, bfd_size_type);
 extern void *bfd_zmalloc
   (bfd_size_type);
+extern void *bfd_malloc2
+  (bfd_size_type, bfd_size_type);
+extern void *bfd_realloc2
+  (void *, bfd_size_type, bfd_size_type);
+extern void *bfd_zmalloc2
+  (bfd_size_type, bfd_size_type);
 
 extern void _bfd_default_error_handler (const char *s, ...);
 extern bfd_error_handler_type _bfd_error_handler;
@@ -108,6 +114,10 @@ extern void *bfd_alloc
   (bfd *, bfd_size_type);
 extern void *bfd_zalloc
   (bfd *, bfd_size_type);
+extern void *bfd_alloc2
+  (bfd *, bfd_size_type, bfd_size_type);
+extern void *bfd_zalloc2
+  (bfd *, bfd_size_type, bfd_size_type);
 extern void bfd_release
   (bfd *, void *);
 

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]