This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB 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] ignore invalid DOF provider sections


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

commit 47e9c225c1cb6fb1809218f5f546a70fc85f705c
Author: Joel Brobecker <brobecker@adacore.com>
Date:   Thu Aug 6 22:13:32 2015 +0200

    ignore invalid DOF provider sections
    
    On x86-solaris 10, we noticed that starting a program would sometimes
    cause the debugger to crash. For instance:
    
        % gdb a
        (gdb) break adainit
        Breakpoint 1 at 0x8051f03
        (gdb) run
        Starting program: /[...]/a
        [Thread debugging using libthread_db enabled]
        zsh: 24398 segmentation fault (core dumped)  /[...]/gdb a
    
    The exception occurs in dtrace_process_dof_probe, while trying
    to process each probe referenced by a DTRACE_DOF_SECT_TYPE_PROVIDER
    DOF section from /lib/libc.so.1. For reference, the ELF section
    in that shared library providing the DOF data has the following
    characteristics:
    
        Idx Name          Size      VMA       LMA       File off  Algn
         14 .SUNW_dof     0000109d  000b4398  000b4398  000b4398  2**3
                          CONTENTS, ALLOC, LOAD, READONLY, DATA
    
    The function dtrace_process_dof gets passed the contents of that
    ELF section, which allows it to determine the location of the table
    where all DOF sections are described. I dumped the contents of
    each DOF section as seen by GDB, and it seemed to be plausible,
    because the offset of each DOF section was pretty much equal to
    the sum of the offset and size of the previous DOF section. Also,
    the offset + sum of the last section corresponds to the size of
    the .SUNW_dof section.
    
    Things start to break down when processing one of the DOF sections
    that has a type of DTRACE_DOF_SECT_TYPE_PROVIDER. It gets the contents
    of this DOF section via:
    
            struct dtrace_dof_provider *provider = (struct dtrace_dof_provider *)
              DTRACE_DOF_PTR (dof, DOF_UINT (dof, section->dofs_offset));
    
    Said more simply, the struct dtrace_dof_provider data is at
    section->dofs_offset of the entire DOF contents. Given that
    the contents of SECTION seemed to make sense, so far so good.
    
    However, what SECTION tells us is that our DOF provider section
    is 40 bytes long:
    
        (gdb) print *section
        $36 = {dofs_type = 15, dofs_align = 4, dofs_flags = 1,
               dofs_entsize = 0, dofs_offset = 3264, dofs_size = 40}
                                                     ^^^^^^^^^^^^^^
    
    But on the other hand:
    
        (gdb) p sizeof (struct dtrace_dof_provider)
        $54 = 44
    
    In other words GDB expected a bigger DOF section and when we try to
    fetch the value of the last field of that DOF section (dofpv_prenoffs)...
    
        eoffsets_s = DTRACE_DOF_SECT (dof,
                                      DOF_UINT (dof, provider->dofpv_prenoffs));
    
    ... we end up reading data that actually belongs to another DOF
    section, and therefore irrelevant. This in turn means that the value
    of eofftab gets incorrectly set, since it depends on eoffsets_s:
    
        eofftab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, eoffsets_s->dofs_offset));
    
    This invalid address quickly catches up to us when we pass it to
    dtrace_process_dof_probe shortly after, where we crash because
    we try to subscript it:
    
        Program received signal SIGSEGV, Segmentation fault.
        0x08155bba in dtrace_process_dof_probe ([...]) at [...]/dtrace-probe.c:378
        378             = ((uint32_t *) eofftab)[...];
    
    This patch fixes the issue by detecting provider DOF sections
    that are smaller than expected, and discarding the DOF data.
    
    gdb/ChangeLog:
    
            * dtrace-probe.c (dtrace_process_dof): Ignore the objfile's DOF
            data if a DTRACE_DOF_SECT_TYPE_PROVIDER section is found to be
            smaller than expected.

Diff:
---
 gdb/ChangeLog      | 6 ++++++
 gdb/dtrace-probe.c | 8 ++++++++
 2 files changed, 14 insertions(+)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ce42136..67a61d8 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,9 @@
+2015-08-07  Joel Brobecker  <brobecker@adacore.com>
+
+	* dtrace-probe.c (dtrace_process_dof): Ignore the objfile's DOF
+	data if a DTRACE_DOF_SECT_TYPE_PROVIDER section is found to be
+	smaller than expected.
+
 2015-08-07  Andrew Burgess  <andrew.burgess@embecosm.com>
 
 	* stack.c (get_frame_language): Moved ...
diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
index 3f2548d..9816f07 100644
--- a/gdb/dtrace-probe.c
+++ b/gdb/dtrace-probe.c
@@ -519,6 +519,14 @@ dtrace_process_dof (asection *sect, struct objfile *objfile,
 	unsigned int entsize = DOF_UINT (dof, probes_s->dofs_entsize);
 	int num_probes;
 
+	if (DOF_UINT (dof, section->dofs_size)
+	    < sizeof (struct dtrace_dof_provider))
+	  {
+	    /* The section is smaller than expected, so do not use it.
+	       This has been observed on x86-solaris 10.  */
+	    goto invalid_dof_data;
+	  }
+
 	/* Very, unlikely, but could crash gdb if not handled
 	   properly.  */
 	if (entsize == 0)


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