This is the mail archive of the binutils@sourceware.org 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]

Test for overflow in eh_frame_hdr entries and for overlapping FDEs


With larger binaries on 64-bit systems, or indeed just binaries that
have a large gap between text and data, it is possible for the
.eh_frame_hdr lookup table entry values to overflow a signed 32-bit
relative offset.  It is also a requirement for the glibc FDE lookup
code that only one FDE claim to cover any given address.

	* elf-bfd.h (struct eh_frame_array_ent): Add "range".
	* elf-eh-frame.c (_bfd_elf_write_section_eh_frame): Stash address
	range of FDEs to hdr_info->array.
	(_bfd_elf_write_section_eh_frame_hdr): Report overflow in
	.eh_frame_hdr entries, and overlapping FDEs.

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 2f24274..dc343ec 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -372,6 +372,7 @@ struct eh_frame_sec_info
 struct eh_frame_array_ent
 {
   bfd_vma initial_loc;
+  bfd_size_type range;
   bfd_vma fde;
 };
 
diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c
index d56440c..02f2d23 100644
--- a/bfd/elf-eh-frame.c
+++ b/bfd/elf-eh-frame.c
@@ -1632,6 +1632,8 @@ _bfd_elf_write_section_eh_frame (bfd *abfd,
 	      if (sizeof (address) > 4 && ptr_size == 4)
 		address &= 0xffffffff;
 	      hdr_info->array[hdr_info->array_count].initial_loc = address;
+	      hdr_info->array[hdr_info->array_count].range
+		= read_value (abfd, buf + width, width, FALSE);
 	      hdr_info->array[hdr_info->array_count++].fde
 		= (sec->output_section->vma
 		   + sec->output_offset
@@ -1805,26 +1807,55 @@ _bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info)
       if (contents[2] != DW_EH_PE_omit)
 	{
 	  unsigned int i;
+	  bfd_boolean overlap, overflow;
 
 	  bfd_put_32 (abfd, hdr_info->fde_count, contents + EH_FRAME_HDR_SIZE);
 	  qsort (hdr_info->array, hdr_info->fde_count,
 		 sizeof (*hdr_info->array), vma_compare);
+	  overlap = FALSE;
+	  overflow = FALSE;
 	  for (i = 0; i < hdr_info->fde_count; i++)
 	    {
-	      bfd_put_32 (abfd,
-			  hdr_info->array[i].initial_loc
-			  - sec->output_section->vma,
-			  contents + EH_FRAME_HDR_SIZE + i * 8 + 4);
-	      bfd_put_32 (abfd,
-			  hdr_info->array[i].fde - sec->output_section->vma,
-			  contents + EH_FRAME_HDR_SIZE + i * 8 + 8);
+	      bfd_vma val;
+
+	      val = hdr_info->array[i].initial_loc - sec->output_section->vma;
+	      val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
+	      if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64
+		  && (hdr_info->array[i].initial_loc
+		      != sec->output_section->vma + val))
+		overflow = TRUE;
+	      bfd_put_32 (abfd, val, contents + EH_FRAME_HDR_SIZE + i * 8 + 4);
+	      val = hdr_info->array[i].fde - sec->output_section->vma;
+	      val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
+	      if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64
+		  && (hdr_info->array[i].fde
+		      != sec->output_section->vma + val))
+		overflow = TRUE;
+	      bfd_put_32 (abfd, val, contents + EH_FRAME_HDR_SIZE + i * 8 + 8);
+	      if (i != 0
+		  && (hdr_info->array[i].initial_loc
+		      < (hdr_info->array[i - 1].initial_loc
+			 + hdr_info->array[i - 1].range)))
+		overlap = TRUE;
+	    }
+	  if (overflow)
+	    (*info->callbacks->einfo)
+	      (_("%P: .eh_frame_hdr entry overflow.\n"));
+	  if (overlap)
+	    (*info->callbacks->einfo)
+	      (_("%P: .eh_frame_hdr refers to overlapping FDEs.\n"));
+	  if (overflow || overlap)
+	    {
+	      bfd_set_error (bfd_error_bad_value);
+	      retval = FALSE;
 	    }
 	}
 
       /* FIXME: octets_per_byte.  */
-      retval = bfd_set_section_contents (abfd, sec->output_section, contents,
-					 (file_ptr) sec->output_offset,
-					 sec->size);
+      if (!bfd_set_section_contents (abfd, sec->output_section, contents,
+				     (file_ptr) sec->output_offset,
+				     sec->size))
+	retval = FALSE;
       free (contents);
     }
   if (hdr_info->array != NULL)

-- 
Alan Modra
Australia Development Lab, IBM


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