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

[binutils-gdb] Fix memory access violations triggered by running addr2line on fuzzed binaries.


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=dbb3fbbb1a3b387a0d33dfd5764cf92bc3da7f41

commit dbb3fbbb1a3b387a0d33dfd5764cf92bc3da7f41
Author: Nick Clifton <nickc@redhat.com>
Date:   Thu Feb 12 16:45:11 2015 +0000

    Fix memory access violations triggered by running addr2line on fuzzed binaries.
    
    	PR binutils/17512
    	* dwarf.c (read_1_byte, read_1_signed_byte, read_2_bytes)
    	(read_4_bytes, read_8_bytes, read_n_bytes, read_string)
    	(read_indirect_string, read_alt_indirect_string)
    	(read_alt_indirect_ref, read_address, read_abbrevs)
    	(read_attribute_value, read_attribute, decode_line_info)
    	(find_abstract_instance_name, read_rangelist)
    	(scan_unit_for_symbols, parse_comp_unit)
    	(_bfd_dwarf2_find_nearest_line): Harden DWARF reading code.  Pass
    	end pointers to reading functions and check for offsets taking
    	pointers out of range.  Replace calls to read_*_leb128 with calls
    	to safe_read_leb128.
    
    	(* elf64-ppc.c (opd_entry_value): Add a check for an overlarge
    	offset.
    	* syms.c (_bfd_stab_section_find_nearest_line): Add checks for
    	computed file_name address being before the start of the string
    	table.

Diff:
---
 bfd/ChangeLog   |  21 +++
 bfd/dwarf2.c    | 408 ++++++++++++++++++++++++++++++++++++++------------------
 bfd/elf64-ppc.c |   4 +
 bfd/syms.c      |   9 +-
 4 files changed, 308 insertions(+), 134 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index d418894..1dd74d0 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,24 @@
+2015-02-12  Nick Clifton  <nickc@redhat.com>
+
+	PR binutils/17512
+	* dwarf.c (read_1_byte, read_1_signed_byte, read_2_bytes)
+	(read_4_bytes, read_8_bytes, read_n_bytes, read_string)
+	(read_indirect_string, read_alt_indirect_string)
+	(read_alt_indirect_ref, read_address, read_abbrevs)
+	(read_attribute_value, read_attribute, decode_line_info)
+	(find_abstract_instance_name, read_rangelist)
+	(scan_unit_for_symbols, parse_comp_unit)
+	(_bfd_dwarf2_find_nearest_line): Harden DWARF reading code.  Pass
+	end pointers to reading functions and check for offsets taking
+	pointers out of range.  Replace calls to read_*_leb128 with calls
+	to safe_read_leb128.
+
+	(* elf64-ppc.c (opd_entry_value): Add a check for an overlarge
+	offset.
+	* syms.c (_bfd_stab_section_find_nearest_line): Add checks for
+	computed file_name address being before the start of the string
+	table.
+
 2015-02-11  H.J. Lu  <hongjiu.lu@intel.com>
 
 	PR ld/17878
diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c
index ccc1365..d884312 100644
--- a/bfd/dwarf2.c
+++ b/bfd/dwarf2.c
@@ -556,83 +556,124 @@ read_section (bfd *           abfd,
   return TRUE;
 }
 
-/* VERBATIM
-   The following function up to the END VERBATIM mark are
-   copied directly from dwarf2read.c.  */
-
 /* Read dwarf information from a buffer.  */
 
 static unsigned int
-read_1_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf)
+read_1_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf, bfd_byte *end)
 {
+  if (buf + 1 > end)
+    return 0;
   return bfd_get_8 (abfd, buf);
 }
 
 static int
-read_1_signed_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf)
+read_1_signed_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf, bfd_byte *end)
 {
+  if (buf + 1 > end)
+    return 0;
   return bfd_get_signed_8 (abfd, buf);
 }
 
 static unsigned int
-read_2_bytes (bfd *abfd, bfd_byte *buf)
+read_2_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end)
 {
+  if (buf + 2 > end)
+    return 0;
   return bfd_get_16 (abfd, buf);
 }
 
 static unsigned int
-read_4_bytes (bfd *abfd, bfd_byte *buf)
+read_4_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end)
 {
+  if (buf + 4 > end)
+    return 0;
   return bfd_get_32 (abfd, buf);
 }
 
 static bfd_uint64_t
-read_8_bytes (bfd *abfd, bfd_byte *buf)
+read_8_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end)
 {
+  if (buf + 8 > end)
+    return 0;
   return bfd_get_64 (abfd, buf);
 }
 
 static bfd_byte *
 read_n_bytes (bfd *abfd ATTRIBUTE_UNUSED,
 	      bfd_byte *buf,
+	      bfd_byte *end,
 	      unsigned int size ATTRIBUTE_UNUSED)
 {
+  if (buf + size > end)
+    return NULL;
   return buf;
 }
 
+/* Scans a NUL terminated string starting at BUF, returning a pointer to it.
+   Returns the number of characters in the string, *including* the NUL byte,
+   in BYTES_READ_PTR.  This value is set even if the function fails.  Bytes
+   at or beyond BUF_END will not be read.  Returns NULL if there was a
+   problem, or if the string is empty.  */
+
 static char *
-read_string (bfd *abfd ATTRIBUTE_UNUSED,
-	     bfd_byte *buf,
-	     unsigned int *bytes_read_ptr)
+read_string (bfd *          abfd ATTRIBUTE_UNUSED,
+	     bfd_byte *     buf,
+	     bfd_byte *     buf_end,
+	     unsigned int * bytes_read_ptr)
 {
-  /* Return a pointer to the embedded string.  */
-  char *str = (char *) buf;
+  bfd_byte *str = buf;
+
+  if (buf >= buf_end)
+    {
+      * bytes_read_ptr = 0;
+      return NULL;
+    }
 
   if (*str == '\0')
     {
-      *bytes_read_ptr = 1;
+      * bytes_read_ptr = 1;
       return NULL;
     }
 
-  *bytes_read_ptr = strlen (str) + 1;
-  return str;
+  while (buf < buf_end)
+    if (* buf ++ == 0)
+      {
+	* bytes_read_ptr = buf - str;
+	return (char *) str;
+      }
+
+  * bytes_read_ptr = buf - str;
+  return NULL;
 }
 
-/* END VERBATIM */
+/* Reads an offset from BUF and then locates the string at this offset
+   inside the debug string section.  Returns a pointer to the string.
+   Returns the number of bytes read from BUF, *not* the length of the string,
+   in BYTES_READ_PTR.  This value is set even if the function fails.  Bytes
+   at or beyond BUF_END will not be read from BUF.  Returns NULL if there was
+   a problem, or if the string is empty.  Does not check for NUL termination
+   of the string.  */
 
 static char *
 read_indirect_string (struct comp_unit * unit,
 		      bfd_byte *         buf,
+		      bfd_byte *         buf_end,
 		      unsigned int *     bytes_read_ptr)
 {
   bfd_uint64_t offset;
   struct dwarf2_debug *stash = unit->stash;
   char *str;
 
+  if (buf + unit->offset_size > buf_end)
+    {
+      * bytes_read_ptr = 0;
+      return NULL;
+    }
+  
   if (unit->offset_size == 4)
-    offset = read_4_bytes (unit->abfd, buf);
+    offset = read_4_bytes (unit->abfd, buf, buf_end);
   else
-    offset = read_8_bytes (unit->abfd, buf);
+    offset = read_8_bytes (unit->abfd, buf, buf_end);
 
   *bytes_read_ptr = unit->offset_size;
 
@@ -641,6 +682,8 @@ read_indirect_string (struct comp_unit * unit,
 		      &stash->dwarf_str_buffer, &stash->dwarf_str_size))
     return NULL;
 
+  if (offset >= stash->dwarf_str_size)
+    return NULL;
   str = (char *) stash->dwarf_str_buffer + offset;
   if (*str == '\0')
     return NULL;
@@ -654,16 +697,23 @@ read_indirect_string (struct comp_unit * unit,
 static char *
 read_alt_indirect_string (struct comp_unit * unit,
 			  bfd_byte *         buf,
+			  bfd_byte *         buf_end,
 			  unsigned int *     bytes_read_ptr)
 {
   bfd_uint64_t offset;
   struct dwarf2_debug *stash = unit->stash;
   char *str;
 
+  if (buf + unit->offset_size > buf_end)
+    {
+      * bytes_read_ptr = 0;
+      return NULL;
+    }
+  
   if (unit->offset_size == 4)
-    offset = read_4_bytes (unit->abfd, buf);
+    offset = read_4_bytes (unit->abfd, buf, buf_end);
   else
-    offset = read_8_bytes (unit->abfd, buf);
+    offset = read_8_bytes (unit->abfd, buf, buf_end);
 
   *bytes_read_ptr = unit->offset_size;
 
@@ -696,6 +746,8 @@ read_alt_indirect_string (struct comp_unit * unit,
 		      &stash->alt_dwarf_str_size))
     return NULL;
 
+  if (offset >= stash->alt_dwarf_str_size)
+    return NULL;
   str = (char *) stash->alt_dwarf_str_buffer + offset;
   if (*str == '\0')
     return NULL;
@@ -742,17 +794,22 @@ read_alt_indirect_ref (struct comp_unit * unit,
 		      &stash->alt_dwarf_info_size))
     return NULL;
 
+  if (offset >= stash->alt_dwarf_info_size)
+    return NULL;
   return stash->alt_dwarf_info_buffer + offset;
 }
 
 static bfd_uint64_t
-read_address (struct comp_unit *unit, bfd_byte *buf)
+read_address (struct comp_unit *unit, bfd_byte *buf, bfd_byte * buf_end)
 {
   int signed_vma = 0;
 
   if (bfd_get_flavour (unit->abfd) == bfd_target_elf_flavour)
     signed_vma = get_elf_backend_data (unit->abfd)->sign_extend_vma;
 
+  if (buf + unit->addr_size > buf_end)
+    return 0;
+
   if (signed_vma)
     {
       switch (unit->addr_size)
@@ -815,6 +872,7 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash)
 {
   struct abbrev_info **abbrevs;
   bfd_byte *abbrev_ptr;
+  bfd_byte *abbrev_end;
   struct abbrev_info *cur_abbrev;
   unsigned int abbrev_number, bytes_read, abbrev_name;
   unsigned int abbrev_form, hash_number;
@@ -825,13 +883,17 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash)
 		      &stash->dwarf_abbrev_buffer, &stash->dwarf_abbrev_size))
     return NULL;
 
+  if (offset >= stash->dwarf_abbrev_size)
+    return NULL;
+
   amt = sizeof (struct abbrev_info*) * ABBREV_HASH_SIZE;
   abbrevs = (struct abbrev_info **) bfd_zalloc (abfd, amt);
   if (abbrevs == NULL)
     return NULL;
 
   abbrev_ptr = stash->dwarf_abbrev_buffer + offset;
-  abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+  abbrev_end = stash->dwarf_abbrev_buffer + stash->dwarf_abbrev_size;
+  abbrev_number = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end);
   abbrev_ptr += bytes_read;
 
   /* Loop until we reach an abbrev number of 0.  */
@@ -845,15 +907,15 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash)
       /* Read in abbrev header.  */
       cur_abbrev->number = abbrev_number;
       cur_abbrev->tag = (enum dwarf_tag)
-	read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+	safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end);
       abbrev_ptr += bytes_read;
-      cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr);
+      cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr, abbrev_end);
       abbrev_ptr += 1;
 
       /* Now read in declarations.  */
-      abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+      abbrev_name = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end);
       abbrev_ptr += bytes_read;
-      abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+      abbrev_form = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end);
       abbrev_ptr += bytes_read;
 
       while (abbrev_name)
@@ -888,9 +950,9 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash)
 	    = (enum dwarf_attribute) abbrev_name;
 	  cur_abbrev->attrs[cur_abbrev->num_attrs++].form
 	    = (enum dwarf_form) abbrev_form;
-	  abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+	  abbrev_name = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end);
 	  abbrev_ptr += bytes_read;
-	  abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+	  abbrev_form = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end);
 	  abbrev_ptr += bytes_read;
 	}
 
@@ -908,9 +970,9 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash)
       if ((unsigned int) (abbrev_ptr - stash->dwarf_abbrev_buffer)
 	  >= stash->dwarf_abbrev_size)
 	break;
-      abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read);
+      abbrev_number = safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, FALSE, abbrev_end);
       abbrev_ptr += bytes_read;
-      if (lookup_abbrev (abbrev_number,abbrevs) != NULL)
+      if (lookup_abbrev (abbrev_number, abbrevs) != NULL)
 	break;
     }
 
@@ -925,19 +987,29 @@ is_str_attr (enum dwarf_form form)
   return form == DW_FORM_string || form == DW_FORM_strp || form == DW_FORM_GNU_strp_alt;
 }
 
-/* Read an attribute value described by an attribute form.  */
+/* Read and fill in the value of attribute ATTR as described by FORM.
+   Read data starting from INFO_PTR, but never at or beyond INFO_PTR_END.
+   Returns an updated INFO_PTR taking into account the amount of data read.  */
 
 static bfd_byte *
-read_attribute_value (struct attribute *attr,
-		      unsigned form,
-		      struct comp_unit *unit,
-		      bfd_byte *info_ptr)
+read_attribute_value (struct attribute *  attr,
+		      unsigned            form,
+		      struct comp_unit *  unit,
+		      bfd_byte *          info_ptr,
+		      bfd_byte *          info_ptr_end)
 {
   bfd *abfd = unit->abfd;
   unsigned int bytes_read;
   struct dwarf_block *blk;
   bfd_size_type amt;
 
+  if (info_ptr >= info_ptr_end)
+    {
+      (*_bfd_error_handler) (_("Dwarf Error: Info pointer extends beyond end of attributes"));
+      bfd_set_error (bfd_error_bad_value);
+      return info_ptr;
+    }
+
   attr->form = (enum dwarf_form) form;
 
   switch (form)
@@ -948,23 +1020,23 @@ read_attribute_value (struct attribute *attr,
       if (unit->version == 3 || unit->version == 4)
 	{
 	  if (unit->offset_size == 4)
-	    attr->u.val = read_4_bytes (unit->abfd, info_ptr);
+	    attr->u.val = read_4_bytes (unit->abfd, info_ptr, info_ptr_end);
 	  else
-	    attr->u.val = read_8_bytes (unit->abfd, info_ptr);
+	    attr->u.val = read_8_bytes (unit->abfd, info_ptr, info_ptr_end);
 	  info_ptr += unit->offset_size;
 	  break;
 	}
       /* FALLTHROUGH */
     case DW_FORM_addr:
-      attr->u.val = read_address (unit, info_ptr);
+      attr->u.val = read_address (unit, info_ptr, info_ptr_end);
       info_ptr += unit->addr_size;
       break;
     case DW_FORM_GNU_ref_alt:
     case DW_FORM_sec_offset:
       if (unit->offset_size == 4)
-	attr->u.val = read_4_bytes (unit->abfd, info_ptr);
+	attr->u.val = read_4_bytes (unit->abfd, info_ptr, info_ptr_end);
       else
-	attr->u.val = read_8_bytes (unit->abfd, info_ptr);
+	attr->u.val = read_8_bytes (unit->abfd, info_ptr, info_ptr_end);
       info_ptr += unit->offset_size;
       break;
     case DW_FORM_block2:
@@ -972,9 +1044,9 @@ read_attribute_value (struct attribute *attr,
       blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
       if (blk == NULL)
 	return NULL;
-      blk->size = read_2_bytes (abfd, info_ptr);
+      blk->size = read_2_bytes (abfd, info_ptr, info_ptr_end);
       info_ptr += 2;
-      blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+      blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size);
       info_ptr += blk->size;
       attr->u.blk = blk;
       break;
@@ -983,34 +1055,34 @@ read_attribute_value (struct attribute *attr,
       blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
       if (blk == NULL)
 	return NULL;
-      blk->size = read_4_bytes (abfd, info_ptr);
+      blk->size = read_4_bytes (abfd, info_ptr, info_ptr_end);
       info_ptr += 4;
-      blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+      blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size);
       info_ptr += blk->size;
       attr->u.blk = blk;
       break;
     case DW_FORM_data2:
-      attr->u.val = read_2_bytes (abfd, info_ptr);
+      attr->u.val = read_2_bytes (abfd, info_ptr, info_ptr_end);
       info_ptr += 2;
       break;
     case DW_FORM_data4:
-      attr->u.val = read_4_bytes (abfd, info_ptr);
+      attr->u.val = read_4_bytes (abfd, info_ptr, info_ptr_end);
       info_ptr += 4;
       break;
     case DW_FORM_data8:
-      attr->u.val = read_8_bytes (abfd, info_ptr);
+      attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end);
       info_ptr += 8;
       break;
     case DW_FORM_string:
-      attr->u.str = read_string (abfd, info_ptr, &bytes_read);
+      attr->u.str = read_string (abfd, info_ptr, info_ptr_end, &bytes_read);
       info_ptr += bytes_read;
       break;
     case DW_FORM_strp:
-      attr->u.str = read_indirect_string (unit, info_ptr, &bytes_read);
+      attr->u.str = read_indirect_string (unit, info_ptr, info_ptr_end, &bytes_read);
       info_ptr += bytes_read;
       break;
     case DW_FORM_GNU_strp_alt:
-      attr->u.str = read_alt_indirect_string (unit, info_ptr, &bytes_read);
+      attr->u.str = read_alt_indirect_string (unit, info_ptr, info_ptr_end, &bytes_read);
       info_ptr += bytes_read;
       break;
     case DW_FORM_exprloc:
@@ -1019,9 +1091,9 @@ read_attribute_value (struct attribute *attr,
       blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
       if (blk == NULL)
 	return NULL;
-      blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+      blk->size = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end);
       info_ptr += bytes_read;
-      blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+      blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size);
       info_ptr += blk->size;
       attr->u.blk = blk;
       break;
@@ -1030,59 +1102,59 @@ read_attribute_value (struct attribute *attr,
       blk = (struct dwarf_block *) bfd_alloc (abfd, amt);
       if (blk == NULL)
 	return NULL;
-      blk->size = read_1_byte (abfd, info_ptr);
+      blk->size = read_1_byte (abfd, info_ptr, info_ptr_end);
       info_ptr += 1;
-      blk->data = read_n_bytes (abfd, info_ptr, blk->size);
+      blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size);
       info_ptr += blk->size;
       attr->u.blk = blk;
       break;
     case DW_FORM_data1:
-      attr->u.val = read_1_byte (abfd, info_ptr);
+      attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end);
       info_ptr += 1;
       break;
     case DW_FORM_flag:
-      attr->u.val = read_1_byte (abfd, info_ptr);
+      attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end);
       info_ptr += 1;
       break;
     case DW_FORM_flag_present:
       attr->u.val = 1;
       break;
     case DW_FORM_sdata:
-      attr->u.sval = read_signed_leb128 (abfd, info_ptr, &bytes_read);
+      attr->u.sval = safe_read_leb128 (abfd, info_ptr, &bytes_read, TRUE, info_ptr_end);
       info_ptr += bytes_read;
       break;
     case DW_FORM_udata:
-      attr->u.val = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+      attr->u.val = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end);
       info_ptr += bytes_read;
       break;
     case DW_FORM_ref1:
-      attr->u.val = read_1_byte (abfd, info_ptr);
+      attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end);
       info_ptr += 1;
       break;
     case DW_FORM_ref2:
-      attr->u.val = read_2_bytes (abfd, info_ptr);
+      attr->u.val = read_2_bytes (abfd, info_ptr, info_ptr_end);
       info_ptr += 2;
       break;
     case DW_FORM_ref4:
-      attr->u.val = read_4_bytes (abfd, info_ptr);
+      attr->u.val = read_4_bytes (abfd, info_ptr, info_ptr_end);
       info_ptr += 4;
       break;
     case DW_FORM_ref8:
-      attr->u.val = read_8_bytes (abfd, info_ptr);
+      attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end);
       info_ptr += 8;
       break;
     case DW_FORM_ref_sig8:
-      attr->u.val = read_8_bytes (abfd, info_ptr);
+      attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end);
       info_ptr += 8;
       break;
     case DW_FORM_ref_udata:
-      attr->u.val = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+      attr->u.val = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end);
       info_ptr += bytes_read;
       break;
     case DW_FORM_indirect:
-      form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+      form = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end);
       info_ptr += bytes_read;
-      info_ptr = read_attribute_value (attr, form, unit, info_ptr);
+      info_ptr = read_attribute_value (attr, form, unit, info_ptr, info_ptr_end);
       break;
     default:
       (*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %#x."),
@@ -1096,13 +1168,14 @@ read_attribute_value (struct attribute *attr,
 /* Read an attribute described by an abbreviated attribute.  */
 
 static bfd_byte *
-read_attribute (struct attribute *attr,
-		struct attr_abbrev *abbrev,
-		struct comp_unit *unit,
-		bfd_byte *info_ptr)
+read_attribute (struct attribute *    attr,
+		struct attr_abbrev *  abbrev,
+		struct comp_unit *    unit,
+		bfd_byte *            info_ptr,
+		bfd_byte *            info_ptr_end)
 {
   attr->name = abbrev->name;
-  info_ptr = read_attribute_value (attr, abbrev->form, unit, info_ptr);
+  info_ptr = read_attribute_value (attr, abbrev->form, unit, info_ptr, info_ptr_end);
   return info_ptr;
 }
 
@@ -1388,6 +1461,8 @@ concat_filename (struct line_info_table *table, unsigned int file)
       size_t len;
 
       if (table->files[file - 1].dir
+	  /* PR 17512: file: 0317e960.  */
+	  && table->files[file - 1].dir <= table->num_dirs
 	  /* PR 17512: file: 7f3d2e4b.  */
 	  && table->dirs != NULL)
 	subdir_name = table->dirs[table->files[file - 1].dir - 1];
@@ -1610,27 +1685,47 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
 
   table->lcl_head = NULL;
 
+  if (stash->dwarf_line_size < 16)
+    {
+      (*_bfd_error_handler)
+	(_("Dwarf Error: Line info section is too small (%ld)"),
+	 (long) stash->dwarf_line_size);
+      bfd_set_error (bfd_error_bad_value);
+      return NULL;
+    }
   line_ptr = stash->dwarf_line_buffer + unit->line_offset;
+  line_end = stash->dwarf_line_buffer + stash->dwarf_line_size;
 
   /* Read in the prologue.  */
-  lh.total_length = read_4_bytes (abfd, line_ptr);
+  lh.total_length = read_4_bytes (abfd, line_ptr, line_end);
   line_ptr += 4;
   offset_size = 4;
   if (lh.total_length == 0xffffffff)
     {
-      lh.total_length = read_8_bytes (abfd, line_ptr);
+      lh.total_length = read_8_bytes (abfd, line_ptr, line_end);
       line_ptr += 8;
       offset_size = 8;
     }
   else if (lh.total_length == 0 && unit->addr_size == 8)
     {
       /* Handle (non-standard) 64-bit DWARF2 formats.  */
-      lh.total_length = read_4_bytes (abfd, line_ptr);
+      lh.total_length = read_4_bytes (abfd, line_ptr, line_end);
       line_ptr += 4;
       offset_size = 8;
     }
+
+  if (lh.total_length > stash->dwarf_line_size)
+    {
+      (*_bfd_error_handler)
+	(_("Dwarf Error: Line info data is bigger (0x%lx) than the section (0x%lx)"),
+	 (long) lh.total_length, (long) stash->dwarf_line_size);
+      bfd_set_error (bfd_error_bad_value);
+      return NULL;
+    }
+    
   line_end = line_ptr + lh.total_length;
-  lh.version = read_2_bytes (abfd, line_ptr);
+  
+  lh.version = read_2_bytes (abfd, line_ptr, line_end);
   if (lh.version < 2 || lh.version > 4)
     {
       (*_bfd_error_handler)
@@ -1639,20 +1734,32 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
       return NULL;
     }
   line_ptr += 2;
+
+  if (line_ptr + offset_size + (lh.version >=4 ? 6 : 5) >= line_end)
+    {
+      (*_bfd_error_handler)
+	(_("Dwarf Error: Ran out of room reading prologue"));
+      bfd_set_error (bfd_error_bad_value);
+      return NULL;
+    }
+
   if (offset_size == 4)
-    lh.prologue_length = read_4_bytes (abfd, line_ptr);
+    lh.prologue_length = read_4_bytes (abfd, line_ptr, line_end);
   else
-    lh.prologue_length = read_8_bytes (abfd, line_ptr);
+    lh.prologue_length = read_8_bytes (abfd, line_ptr, line_end);
   line_ptr += offset_size;
-  lh.minimum_instruction_length = read_1_byte (abfd, line_ptr);
+
+  lh.minimum_instruction_length = read_1_byte (abfd, line_ptr, line_end);
   line_ptr += 1;
+
   if (lh.version >= 4)
     {
-      lh.maximum_ops_per_insn = read_1_byte (abfd, line_ptr);
+      lh.maximum_ops_per_insn = read_1_byte (abfd, line_ptr, line_end);
       line_ptr += 1;
     }
   else
     lh.maximum_ops_per_insn = 1;
+
   if (lh.maximum_ops_per_insn == 0)
     {
       (*_bfd_error_handler)
@@ -1660,14 +1767,26 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
       bfd_set_error (bfd_error_bad_value);
       return NULL;
     }
-  lh.default_is_stmt = read_1_byte (abfd, line_ptr);
+
+  lh.default_is_stmt = read_1_byte (abfd, line_ptr, line_end);
   line_ptr += 1;
-  lh.line_base = read_1_signed_byte (abfd, line_ptr);
+
+  lh.line_base = read_1_signed_byte (abfd, line_ptr, line_end);
   line_ptr += 1;
-  lh.line_range = read_1_byte (abfd, line_ptr);
+
+  lh.line_range = read_1_byte (abfd, line_ptr, line_end);
   line_ptr += 1;
-  lh.opcode_base = read_1_byte (abfd, line_ptr);
+
+  lh.opcode_base = read_1_byte (abfd, line_ptr, line_end);
   line_ptr += 1;
+
+  if (line_ptr + (lh.opcode_base - 1) >= line_end)
+    {
+      (*_bfd_error_handler) (_("Dwarf Error: Ran out of room reading opcodes"));
+      bfd_set_error (bfd_error_bad_value);
+      return NULL;
+    }
+  
   amt = lh.opcode_base * sizeof (unsigned char);
   lh.standard_opcode_lengths = (unsigned char *) bfd_alloc (abfd, amt);
 
@@ -1675,12 +1794,12 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
 
   for (i = 1; i < lh.opcode_base; ++i)
     {
-      lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr);
+      lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr, line_end);
       line_ptr += 1;
     }
 
   /* Read directory table.  */
-  while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL)
+  while ((cur_dir = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL)
     {
       line_ptr += bytes_read;
 
@@ -1703,7 +1822,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
   line_ptr += bytes_read;
 
   /* Read file name table.  */
-  while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL)
+  while ((cur_file = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL)
     {
       line_ptr += bytes_read;
 
@@ -1722,13 +1841,11 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
 
       table->files[table->num_files].name = cur_file;
       table->files[table->num_files].dir =
-	read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+	safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
       line_ptr += bytes_read;
-      table->files[table->num_files].time =
-	read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+      table->files[table->num_files].time = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
       line_ptr += bytes_read;
-      table->files[table->num_files].size =
-	read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+      table->files[table->num_files].size = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
       line_ptr += bytes_read;
       table->num_files++;
     }
@@ -1758,13 +1875,15 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
       /* Decode the table.  */
       while (! end_sequence)
 	{
-	  op_code = read_1_byte (abfd, line_ptr);
+	  op_code = read_1_byte (abfd, line_ptr, line_end);
 	  line_ptr += 1;
 
 	  if (op_code >= lh.opcode_base)
 	    {
 	      /* Special operand.  */
 	      adj_opcode = op_code - lh.opcode_base;
+	      if (lh.line_range == 0)
+		goto line_fail;
 	      if (lh.maximum_ops_per_insn == 1)
 		address += (adj_opcode / lh.line_range
 			    * lh.minimum_instruction_length);
@@ -1790,9 +1909,9 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
 	  else switch (op_code)
 	    {
 	    case DW_LNS_extended_op:
-	      exop_len = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+	      exop_len = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
 	      line_ptr += bytes_read;
-	      extended_op = read_1_byte (abfd, line_ptr);
+	      extended_op = read_1_byte (abfd, line_ptr, line_end);
 	      line_ptr += 1;
 
 	      switch (extended_op)
@@ -1811,12 +1930,12 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
 		    goto line_fail;
 		  break;
 		case DW_LNE_set_address:
-		  address = read_address (unit, line_ptr);
+		  address = read_address (unit, line_ptr, line_end);
 		  op_index = 0;
 		  line_ptr += unit->addr_size;
 		  break;
 		case DW_LNE_define_file:
-		  cur_file = read_string (abfd, line_ptr, &bytes_read);
+		  cur_file = read_string (abfd, line_ptr, line_end, &bytes_read);
 		  line_ptr += bytes_read;
 		  if ((table->num_files % FILE_ALLOC_CHUNK) == 0)
 		    {
@@ -1831,19 +1950,19 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
 		    }
 		  table->files[table->num_files].name = cur_file;
 		  table->files[table->num_files].dir =
-		    read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+		    safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
 		  line_ptr += bytes_read;
 		  table->files[table->num_files].time =
-		    read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+		    safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
 		  line_ptr += bytes_read;
 		  table->files[table->num_files].size =
-		    read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+		    safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
 		  line_ptr += bytes_read;
 		  table->num_files++;
 		  break;
 		case DW_LNE_set_discriminator:
 		  discriminator =
-		    read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+		    safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
 		  line_ptr += bytes_read;
 		  break;
 		case DW_LNE_HP_source_file_correlation:
@@ -1872,12 +1991,12 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
 	    case DW_LNS_advance_pc:
 	      if (lh.maximum_ops_per_insn == 1)
 		address += (lh.minimum_instruction_length
-			    * read_unsigned_leb128 (abfd, line_ptr,
-						    &bytes_read));
+			    * safe_read_leb128 (abfd, line_ptr, &bytes_read,
+						FALSE, line_end));
 	      else
 		{
-		  bfd_vma adjust = read_unsigned_leb128 (abfd, line_ptr,
-							 &bytes_read);
+		  bfd_vma adjust = safe_read_leb128 (abfd, line_ptr, &bytes_read,
+						     FALSE, line_end);
 		  address = ((op_index + adjust) / lh.maximum_ops_per_insn
 			     * lh.minimum_instruction_length);
 		  op_index = (op_index + adjust) % lh.maximum_ops_per_insn;
@@ -1885,7 +2004,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
 	      line_ptr += bytes_read;
 	      break;
 	    case DW_LNS_advance_line:
-	      line += read_signed_leb128 (abfd, line_ptr, &bytes_read);
+	      line += safe_read_leb128 (abfd, line_ptr, &bytes_read, TRUE, line_end);
 	      line_ptr += bytes_read;
 	      break;
 	    case DW_LNS_set_file:
@@ -1894,7 +2013,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
 
 		/* The file and directory tables are 0
 		   based, the references are 1 based.  */
-		file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+		file = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
 		line_ptr += bytes_read;
 		if (filename)
 		  free (filename);
@@ -1902,7 +2021,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
 		break;
 	      }
 	    case DW_LNS_set_column:
-	      column = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+	      column = safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
 	      line_ptr += bytes_read;
 	      break;
 	    case DW_LNS_negate_stmt:
@@ -1924,7 +2043,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
 		}
 	      break;
 	    case DW_LNS_fixed_advance_pc:
-	      address += read_2_bytes (abfd, line_ptr);
+	      address += read_2_bytes (abfd, line_ptr, line_end);
 	      op_index = 0;
 	      line_ptr += 2;
 	      break;
@@ -1932,7 +2051,7 @@ decode_line_info (struct comp_unit *unit, struct dwarf2_debug *stash)
 	      /* Unknown standard opcode, ignore it.  */
 	      for (i = 0; i < lh.standard_opcode_lengths[op_code]; i++)
 		{
-		  (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+		  (void) safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end);
 		  line_ptr += bytes_read;
 		}
 	      break;
@@ -2161,6 +2280,7 @@ find_abstract_instance_name (struct comp_unit *unit,
 {
   bfd *abfd = unit->abfd;
   bfd_byte *info_ptr;
+  bfd_byte *info_ptr_end;
   unsigned int abbrev_number, bytes_read, i;
   struct abbrev_info *abbrev;
   bfd_uint64_t die_ref = attr_ptr->u.val;
@@ -2177,6 +2297,7 @@ find_abstract_instance_name (struct comp_unit *unit,
 	abort ();
 
       info_ptr = unit->sec_info_ptr + die_ref;
+      info_ptr_end = unit->end_ptr;
 
       /* Now find the CU containing this pointer.  */
       if (info_ptr >= unit->info_ptr_unit && info_ptr < unit->end_ptr)
@@ -2210,13 +2331,18 @@ find_abstract_instance_name (struct comp_unit *unit,
 	  bfd_set_error (bfd_error_bad_value);
 	  return NULL;
 	}
+      info_ptr_end = unit->stash->alt_dwarf_info_buffer + unit->stash->alt_dwarf_info_size;
+
       /* FIXME: Do we need to locate the correct CU, in a similar
 	 fashion to the code in the DW_FORM_ref_addr case above ?  */
     }
   else
-    info_ptr = unit->info_ptr_unit + die_ref;
+    {
+      info_ptr = unit->info_ptr_unit + die_ref;
+      info_ptr_end = unit->end_ptr;
+    }
 
-  abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+  abbrev_number = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end);
   info_ptr += bytes_read;
 
   if (abbrev_number)
@@ -2233,7 +2359,7 @@ find_abstract_instance_name (struct comp_unit *unit,
 	  for (i = 0; i < abbrev->num_attrs; ++i)
 	    {
 	      info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit,
-					 info_ptr);
+					 info_ptr, info_ptr_end);
 	      if (info_ptr == NULL)
 		break;
 	      switch (attr.name)
@@ -2275,6 +2401,7 @@ read_rangelist (struct comp_unit *unit, struct arange *arange,
 		bfd_uint64_t offset)
 {
   bfd_byte *ranges_ptr;
+  bfd_byte *ranges_end;
   bfd_vma base_address = unit->base_address;
 
   if (! unit->stash->dwarf_ranges_buffer)
@@ -2282,16 +2409,24 @@ read_rangelist (struct comp_unit *unit, struct arange *arange,
       if (! read_debug_ranges (unit))
 	return FALSE;
     }
-  ranges_ptr = unit->stash->dwarf_ranges_buffer + offset;
 
+  ranges_ptr = unit->stash->dwarf_ranges_buffer + offset;
+  if (ranges_ptr < unit->stash->dwarf_ranges_buffer)
+    return FALSE;
+  ranges_end = unit->stash->dwarf_ranges_buffer + unit->stash->dwarf_ranges_size;
+  
   for (;;)
     {
       bfd_vma low_pc;
       bfd_vma high_pc;
 
-      low_pc = read_address (unit, ranges_ptr);
+      /* PR 17512: file: 62cada7d.  */
+      if (ranges_ptr + 2 * unit->addr_size >= ranges_end)
+	return FALSE;
+
+      low_pc = read_address (unit, ranges_ptr, ranges_end);
       ranges_ptr += unit->addr_size;
-      high_pc = read_address (unit, ranges_ptr);
+      high_pc = read_address (unit, ranges_ptr, ranges_end);
       ranges_ptr += unit->addr_size;
 
       if (low_pc == 0 && high_pc == 0)
@@ -2318,6 +2453,7 @@ scan_unit_for_symbols (struct comp_unit *unit)
 {
   bfd *abfd = unit->abfd;
   bfd_byte *info_ptr = unit->first_child_die_ptr;
+  bfd_byte *info_ptr_end = unit->stash->info_ptr_end;
   int nesting_level = 1;
   struct funcinfo **nested_funcs;
   int nested_funcs_size;
@@ -2343,10 +2479,10 @@ scan_unit_for_symbols (struct comp_unit *unit)
       bfd_boolean high_pc_relative = FALSE;
 
       /* PR 17512: file: 9f405d9d.  */
-      if (info_ptr >= unit->stash->info_ptr_end)
+      if (info_ptr >= info_ptr_end)
 	goto fail;
       
-      abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+      abbrev_number = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, info_ptr_end);
       info_ptr += bytes_read;
 
       if (! abbrev_number)
@@ -2410,7 +2546,7 @@ scan_unit_for_symbols (struct comp_unit *unit)
 
       for (i = 0; i < abbrev->num_attrs; ++i)
 	{
-	  info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr);
+	  info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr, info_ptr_end);
 	  if (info_ptr == NULL)
 	    goto fail;
 
@@ -2608,15 +2744,15 @@ parse_comp_unit (struct dwarf2_debug *stash,
   bfd *abfd = stash->bfd_ptr;
   bfd_boolean high_pc_relative = FALSE;
 
-  version = read_2_bytes (abfd, info_ptr);
+  version = read_2_bytes (abfd, info_ptr, end_ptr);
   info_ptr += 2;
   BFD_ASSERT (offset_size == 4 || offset_size == 8);
   if (offset_size == 4)
-    abbrev_offset = read_4_bytes (abfd, info_ptr);
+    abbrev_offset = read_4_bytes (abfd, info_ptr, end_ptr);
   else
-    abbrev_offset = read_8_bytes (abfd, info_ptr);
+    abbrev_offset = read_8_bytes (abfd, info_ptr, end_ptr);
   info_ptr += offset_size;
-  addr_size = read_1_byte (abfd, info_ptr);
+  addr_size = read_1_byte (abfd, info_ptr, end_ptr);
   info_ptr += 1;
 
   if (version != 2 && version != 3 && version != 4)
@@ -2653,7 +2789,7 @@ parse_comp_unit (struct dwarf2_debug *stash,
   if (! abbrevs)
     return 0;
 
-  abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
+  abbrev_number = safe_read_leb128 (abfd, info_ptr, &bytes_read, FALSE, end_ptr);
   info_ptr += bytes_read;
   if (! abbrev_number)
     {
@@ -2688,7 +2824,7 @@ parse_comp_unit (struct dwarf2_debug *stash,
 
   for (i = 0; i < abbrev->num_attrs; ++i)
     {
-      info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr);
+      info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr, end_ptr);
       if (info_ptr == NULL)
 	return NULL;
 
@@ -3838,13 +3974,13 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
       unsigned int offset_size = addr_size;
       bfd_byte *info_ptr_unit = stash->info_ptr;
 
-      length = read_4_bytes (stash->bfd_ptr, stash->info_ptr);
+      length = read_4_bytes (stash->bfd_ptr, stash->info_ptr, stash->info_ptr_end);
       /* A 0xffffff length is the DWARF3 way of indicating
 	 we use 64-bit offsets, instead of 32-bit offsets.  */
       if (length == 0xffffffff)
 	{
 	  offset_size = 8;
-	  length = read_8_bytes (stash->bfd_ptr, stash->info_ptr + 4);
+	  length = read_8_bytes (stash->bfd_ptr, stash->info_ptr + 4, stash->info_ptr_end);
 	  stash->info_ptr += 12;
 	}
       /* A zero length is the IRIX way of indicating 64-bit offsets,
@@ -3853,7 +3989,7 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
       else if (length == 0)
 	{
 	  offset_size = 8;
-	  length = read_4_bytes (stash->bfd_ptr, stash->info_ptr + 4);
+	  length = read_4_bytes (stash->bfd_ptr, stash->info_ptr + 4, stash->info_ptr_end);
 	  stash->info_ptr += 8;
 	}
       /* In the absence of the hints above, we assume 32-bit DWARF2
@@ -3875,14 +4011,26 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
 
       if (length > 0)
 	{
+	  bfd_byte * new_ptr;
+
 	  each = parse_comp_unit (stash, length, info_ptr_unit,
 				  offset_size);
 	  if (!each)
 	    /* The dwarf information is damaged, don't trust it any
 	       more.  */
 	    break;
-	  stash->info_ptr += length;
 
+	  new_ptr = stash->info_ptr + length;
+	  /* PR 17512: file: 1500698c.  */
+	  if (new_ptr < stash->info_ptr)
+	    {
+	      /* A corrupt length value - do not trust the info any more.  */
+	      found = FALSE;
+	      break;
+	    }
+	  else	    
+	    stash->info_ptr = new_ptr;
+	  
 	  if (stash->all_comp_units)
 	    stash->all_comp_units->prev_unit = each;
 	  else
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index f821231..542ed1c 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -5951,6 +5951,10 @@ opd_entry_value (asection *opd_sec,
 	  ppc64_elf_tdata (opd_bfd)->opd.contents = contents;
 	}
 
+      /* PR 17512: file: 64b9dfbb.  */
+      if (offset > bfd_section_size (opd_bfd, opd_sec))
+	return (bfd_vma) -1;
+
       val = bfd_get_64 (opd_bfd, contents + offset);
       if (code_sec != NULL)
 	{
diff --git a/bfd/syms.c b/bfd/syms.c
index 0b0d26d..9d7a1f4 100644
--- a/bfd/syms.c
+++ b/bfd/syms.c
@@ -1192,7 +1192,7 @@ _bfd_stab_section_find_nearest_line (bfd *abfd,
 		{
 		  nul_fun = stab;
 		  nul_str = str;
-		  if (file_name >= (char *) info->strs + strsize)
+		  if (file_name >= (char *) info->strs + strsize || file_name < (char *) str)
 		    file_name = NULL;
 		  if (stab + STABSIZE + TYPEOFF < info->stabs + stabsize
 		      && *(stab + STABSIZE + TYPEOFF) == (bfd_byte) N_SO)
@@ -1203,7 +1203,7 @@ _bfd_stab_section_find_nearest_line (bfd *abfd,
 		      directory_name = file_name;
 		      file_name = ((char *) str
 				   + bfd_get_32 (abfd, stab + STRDXOFF));
-		      if (file_name >= (char *) info->strs + strsize)
+		      if (file_name >= (char *) info->strs + strsize || file_name < (char *) str)
 			file_name = NULL;
 		    }
 		}
@@ -1213,7 +1213,8 @@ _bfd_stab_section_find_nearest_line (bfd *abfd,
 	      /* The name of an include file.  */
 	      file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF);
 	      /* PR 17512: file: 0c680a1f.  */
-	      if (file_name >= (char *) info->strs + strsize)
+	      /* PR 17512: file: 5da8aec4.  */
+	      if (file_name >= (char *) info->strs + strsize || file_name < (char *) str)
 		file_name = NULL;
 	      break;
 
@@ -1331,7 +1332,7 @@ _bfd_stab_section_find_nearest_line (bfd *abfd,
 	  if (val <= offset)
 	    {
 	      file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF);
-	      if (file_name >= (char *) info->strs + strsize)
+	      if (file_name >= (char *) info->strs + strsize || file_name < (char *) str)
 		file_name = NULL;
 	      *pline = 0;
 	    }


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