public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* Re: [PATCH]: Improve readelf's handling of corrupt call frames
@ 2006-06-30 13:30 Nick Clifton
  0 siblings, 0 replies; 2+ messages in thread
From: Nick Clifton @ 2006-06-30 13:30 UTC (permalink / raw)
  To: binutils

[-- Attachment #1: Type: text/plain, Size: 64 bytes --]

Oops - forgot to attach the patch.  Here it is.

Cheers
  Nick


[-- Attachment #2: dwarf.c.patch.3 --]
[-- Type: application/octet-stream, Size: 4697 bytes --]

Index: binutils/dwarf.c
===================================================================
RCS file: /cvs/src/src/binutils/dwarf.c,v
retrieving revision 1.5
diff -c -3 -p -r1.5 dwarf.c
*** binutils/dwarf.c	15 May 2006 14:50:38 -0000	1.5
--- binutils/dwarf.c	30 Jun 2006 12:38:12 -0000
*************** display_debug_aranges (struct dwarf_sect
*** 2519,2524 ****
--- 2519,2525 ----
        unsigned char *ranges;
        unsigned long length;
        unsigned long address;
+       unsigned char address_size;
        int excess;
        int offset_size;
        int initial_length_size;
*************** display_debug_aranges (struct dwarf_sect
*** 2565,2590 ****
        printf (_("  Pointer Size:             %d\n"), arange.ar_pointer_size);
        printf (_("  Segment Size:             %d\n"), arange.ar_segment_size);
  
        printf (_("\n    Address  Length\n"));
  
        ranges = hdrptr;
  
!       /* Must pad to an alignment boundary that is twice the pointer size.  */
!       excess = (hdrptr - start) % (2 * arange.ar_pointer_size);
        if (excess)
! 	ranges += (2 * arange.ar_pointer_size) - excess;
  
        start += arange.ar_length + initial_length_size;
  
!       while (ranges + 2 * arange.ar_pointer_size <= start)
  	{
! 	  address = byte_get (ranges, arange.ar_pointer_size);
  
! 	  ranges += arange.ar_pointer_size;
  
! 	  length  = byte_get (ranges, arange.ar_pointer_size);
  
! 	  ranges += arange.ar_pointer_size;
  
  	  printf ("    %8.8lx %lu\n", address, length);
  	}
--- 2566,2602 ----
        printf (_("  Pointer Size:             %d\n"), arange.ar_pointer_size);
        printf (_("  Segment Size:             %d\n"), arange.ar_segment_size);
  
+       address_size = arange.ar_pointer_size + arange.ar_segment_size;
+ 
+       /* The DWARF spec does not require that the address size be a power
+ 	 of two, but we do.  This will have to change if we ever encounter
+ 	 an uneven architecture.  */
+       if ((address_size & (address_size - 1)) != 0)
+ 	{
+ 	  warn (_("Pointer size + Segment size is not a power of two.\n"));
+ 	  break;
+ 	}
+       
        printf (_("\n    Address  Length\n"));
  
        ranges = hdrptr;
  
!       /* Must pad to an alignment boundary that is twice the address size.  */
!       excess = (hdrptr - start) % (2 * address_size);
        if (excess)
! 	ranges += (2 * address_size) - excess;
  
        start += arange.ar_length + initial_length_size;
  
!       while (ranges + 2 * address_size <= start)
  	{
! 	  address = byte_get (ranges, address_size);
  
! 	  ranges += address_size;
  
! 	  length  = byte_get (ranges, address_size);
  
! 	  ranges += address_size;
  
  	  printf ("    %8.8lx %lu\n", address, length);
  	}
*************** static dwarf_vma
*** 2879,2884 ****
--- 2891,2897 ----
  get_encoded_value (unsigned char *data, int encoding)
  {
    int size = size_of_encoded_value (encoding);
+ 
    if (encoding & DW_EH_PE_signed)
      return byte_get_signed (data, size);
    else
*************** display_debug_frames (struct dwarf_secti
*** 2944,2949 ****
--- 2957,2968 ----
  	}
  
        block_end = saved_start + length + initial_length_size;
+       if (block_end > end)
+ 	{
+ 	  warn ("Invalid length %#08lx in FDE at %#08lx\n",
+ 		length, (unsigned long)(saved_start - section_start));
+ 	  block_end = end;
+ 	}
        cie_id = byte_get (start, offset_size); start += offset_size;
  
        if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID))
*************** display_debug_frames (struct dwarf_secti
*** 3078,3086 ****
  
  	  if (!cie)
  	    {
! 	      warn ("Invalid CIE pointer %08lx in FDE at %08lx\n",
  		    cie_id, (unsigned long)(saved_start - section_start));
- 	      start = block_end;
  	      fc->ncols = 0;
  	      fc->col_type = xmalloc (sizeof (short int));
  	      fc->col_offset = xmalloc (sizeof (int));
--- 3097,3104 ----
  
  	  if (!cie)
  	    {
! 	      warn ("Invalid CIE pointer %#08lx in FDE at %#08lx\n",
  		    cie_id, (unsigned long)(saved_start - section_start));
  	      fc->ncols = 0;
  	      fc->col_type = xmalloc (sizeof (short int));
  	      fc->col_offset = xmalloc (sizeof (int));
*************** display_debug_frames (struct dwarf_secti
*** 3584,3590 ****
  	      break;
  
  	    default:
! 	      warn (_("unsupported or unknown DW_CFA_%d\n"), op);
  	      start = block_end;
  	    }
  	}
--- 3602,3611 ----
  	      break;
  
  	    default:
! 	      if (op >= DW_CFA_lo_user && op <= DW_CFA_hi_user)
! 		printf (_("  DW_CFA_??? (User defined call frame op: %#x)\n"), op);
! 	      else
! 		warn (_("unsupported or unknown Dwarf Call Frame Instruction number: %#x\n"), op);		
  	      start = block_end;
  	    }
  	}

^ permalink raw reply	[flat|nested] 2+ messages in thread

* [PATCH]: Improve readelf's handling of corrupt call frames
@ 2006-06-30 12:46 Nick Clifton
  0 siblings, 0 replies; 2+ messages in thread
From: Nick Clifton @ 2006-06-30 12:46 UTC (permalink / raw)
  To: binutils

Hi Guys,

  A coworker recently across a situation where readelf would seg fault
  whilst trying to display the call frame information for a binary
  built for a 16-bit target.  Whilst the issue of whether the call
  frame info in this binary was actually corrupt is still in debate
  (it is a segmented 16/24/32 bit architecture), the fact remains that
  readelf should not seg fault.

  So I am going to apply the attached patch.  It detects situations
  where the end of a call frame data block is beyond the end of the
  .debug_frame section, and it prevents the code that handles corrupt
  CIE pointers from resetting the start pointer to the end of the
  block.  This causes problems because the code later on will attempt
  to read the rest of the block's information from beyond the end of
  the block.

Cheers
  Nick

binutils/ChangeLog
2006-06-30  Nick Clifton  <nickc@redhat.com>

	* dwarf.c (display_debug_frames): Catch a corrupt length field
	generating an end of block address that is beyond the end of the
	section.
	When encountering a corrupt CIE pointer do not reset the start
	pointer as more data still has to be read.
	Do not warn about user defined call frame instructions.


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2006-06-30 12:46 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-06-30 13:30 [PATCH]: Improve readelf's handling of corrupt call frames Nick Clifton
  -- strict thread matches above, loose matches on Subject: below --
2006-06-30 12:46 Nick Clifton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).