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

RFC: Verify AT_ENTRY before using it


I have a lot of occasions to run programs with a non-default dynamic
loader.  Typically, I do this by taking advantage of gdbserver.
In one window, "gdbserver :PORT /path/to/this/loader /path/to/binary".
In the other, "gdb /path/to/binary" and "target remote :PORT".

Starting with the merge of PIE support, this blows up.  GDB tries to
relocate BINARY by the auxv AT_ENTRY value, but AT_ENTRY describes the
loader, not the binary.

I chose to fix this by a program header comparison.  We can fetch
program headers from AT_PHDRS / AT_PHENT / AT_PHNUM, or from the BFD.
If the program headers in both places are the same, the odds are very
good that AT_ENTRY (which will match AT_PHDRS - the kernel handles
that) belongs to the binary we think it does.  If not, give up on
auxv-based relocation.

There's a short-circuit check so that the extra memory read can
be skipped for non-PIE.

I also have a local executable that acts as a proxy dynamic loader.
That triggers the same scenario.

I've tested this on x86_64, where it unbreaks the ld.so scenario
described above.  I'll test it with our proxy loader on ARM tomorrow;
that machine is currently down for maintenance.

Any comments, or shall I commit this?

-- 
Daniel Jacobowitz
CodeSourcery

2010-02-24  Daniel Jacobowitz  <dan@codesourcery.com>

	* solib-svr4.c (read_program_header): Support type == -1 to read
	all program headers.
	(bfd_read_program_headers): New function.
	(svr4_exec_displacement): Verify that AT_ENTRY is associated with
	exec_bfd.

Index: solib-svr4.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-svr4.c,v
retrieving revision 1.125
diff -u -p -r1.125 solib-svr4.c
--- solib-svr4.c	24 Feb 2010 00:29:02 -0000	1.125
+++ solib-svr4.c	24 Feb 2010 22:41:35 -0000
@@ -451,6 +451,9 @@ bfd_lookup_symbol (bfd *abfd, char *symn
 /* Read program header TYPE from inferior memory.  The header is found
    by scanning the OS auxillary vector.
 
+   If TYPE == -1, return the program headers instead of the contents of
+   one program header.
+
    Return a pointer to allocated memory holding the program header contents,
    or NULL on failure.  If sucessful, and unless P_SECT_SIZE is NULL, the
    size of those contents is returned to P_SECT_SIZE.  Likewise, the target
@@ -483,8 +486,13 @@ read_program_header (int type, int *p_se
   else
     return 0;
 
-  /* Find .dynamic section via the PT_DYNAMIC PHDR.  */
-  if (arch_size == 32)
+  /* Find the requested segment.  */
+  if (type == -1)
+    {
+      sect_addr = at_phdr;
+      sect_size = at_phent * at_phnum;
+    }
+  else if (arch_size == 32)
     {
       Elf32_External_Phdr phdr;
       int i;
@@ -1669,6 +1677,29 @@ svr4_static_exec_displacement (void)
   return 0;
 }
 
+static gdb_byte *
+bfd_read_program_headers (bfd *abfd, int *phdrs_size)
+{
+  Elf_Internal_Ehdr *ehdr;
+  gdb_byte *buf;
+
+  ehdr = elf_elfheader (abfd);
+
+  *phdrs_size = ehdr->e_phnum * ehdr->e_phentsize;
+  if (*phdrs_size == 0)
+    return NULL;
+
+  buf = xmalloc (*phdrs_size);
+  if (bfd_seek (abfd, ehdr->e_phoff, SEEK_SET) != 0
+      || bfd_bread (buf, *phdrs_size, abfd) != *phdrs_size)
+    {
+      xfree (buf);
+      return NULL;
+    }
+
+  return buf;
+}
+
 /* We relocate all of the sections by the same amount.  This
    behavior is mandated by recent editions of the System V ABI. 
    According to the System V Application Binary Interface,
@@ -1702,7 +1733,36 @@ svr4_exec_displacement (void)
     return 0;
 
   if (target_auxv_search (&current_target, AT_ENTRY, &entry_point) == 1)
-    return entry_point - bfd_get_start_address (exec_bfd);
+    {
+      /* Verify that the auxilliary vector describes the same file as
+	 exec_bfd, by comparing their program headers.  If the program
+	 headers in the auxilliary vector do not match the program
+	 headers in the executable, then we are looking at a different
+	 file than the one used by the kernel - for instance, "gdb
+	 program" connected to "gdbserver :PORT ld.so program".  */
+      int phdrs_size, phdrs2_size, ok = 0;
+      gdb_byte *buf, *buf2;
+
+      /* Take a shortcut for the common case.  If the entry addresses
+	 match, then it is incredibly unlikely that anything
+	 complicated has happened.  It's not impossible, if the loader
+	 and executable are both PIE, but it would still require a
+	 rare conjunction of load addresses.  */
+      if (entry_point == bfd_get_start_address (exec_bfd))
+	return 0;
+
+      buf = read_program_header (-1, &phdrs_size, NULL);
+      buf2 = bfd_read_program_headers (exec_bfd, &phdrs2_size);
+      if (buf != NULL && buf2 != NULL
+	  && phdrs_size == phdrs2_size
+	  && memcmp (buf, buf2, phdrs_size) == 0)
+	ok = 1;
+      xfree (buf);
+      xfree (buf2);
+
+      if (ok)
+	return entry_point - bfd_get_start_address (exec_bfd);
+    }
 
   return svr4_static_exec_displacement ();
 }


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