submitted-dladdr
authorGNU Libc Maintainers <debian-glibc@lists.debian.org>
Mon, 16 Jan 2017 17:43:37 +0000 (17:43 +0000)
committerAurelien Jarno <aurel32@debian.org>
Mon, 16 Jan 2017 17:43:37 +0000 (17:43 +0000)
2016-05-14  John David Anglin  <danglin@gcc.gnu.org>

[BZ 20098]
* sysdeps/hppa/dl-fptr.c (_dl_read_access_allowed): New.
(_dl_lookup_address): Return address if it is not consistent with
being a linker defined function pointer.  Likewise, return address
if address and function descriptor addresses are not accessible.

Gbp-Pq: Topic hppa
Gbp-Pq: Name submitted-dladdr.diff

sysdeps/hppa/dl-fptr.c

index 04ed10c82e7e0b27b3d6fa497d4cbabcb906b4e4..c1233a1a1d0daa42de75ae8c78f2538b41f96f01 100644 (file)
@@ -337,22 +337,45 @@ elf_machine_resolve (void)
   return addr;
 }
 
+static inline int
+_dl_read_access_allowed (unsigned int *addr)
+{
+  int result;
+
+  asm ("proberi        (%1),3,%0" : "=r" (result) : "r" (addr) : );
+
+  return result;
+}
+
 ElfW(Addr)
 _dl_lookup_address (const void *address)
 {
   ElfW(Addr) addr = (ElfW(Addr)) address;
   unsigned int *desc, *gptr;
 
-  /* Check for special cases.  */
-  if ((int) addr == -1
-      || (unsigned int) addr < 4096
-      || !((unsigned int) addr & 2))
+  /* Return ADDR if the least-significant two bits of ADDR are not consistent
+     with ADDR being a linker defined function pointer.  The normal value for
+     a code address in a backtrace is 3.  */
+  if (((unsigned int) addr & 3) != 2)
+    return addr;
+
+  /* Handle special case where ADDR points to page 0.  */
+  if ((unsigned int) addr < 4096)
     return addr;
 
   /* Clear least-significant two bits from descriptor address.  */
   desc = (unsigned int *) ((unsigned int) addr & ~3);
+  if (!_dl_read_access_allowed (desc))
+    return addr;
+
+  /* Load first word of candidate descriptor.  It should be a pointer
+     with word alignment and point to memory that can be read.  */
+  gptr = (unsigned int *) desc[0];
+  if (((unsigned int) gptr & 3) != 0
+      || !_dl_read_access_allowed (gptr))
+    return addr;
 
-  /* Check if descriptor requires resolution.  The following trampoline is
+  /* See if descriptor requires resolution.  The following trampoline is
      used in each global offset table for function resolution:
 
                ldw 0(r20),r22
@@ -364,7 +387,6 @@ _dl_lookup_address (const void *address)
                .word "_dl_runtime_resolve ltp"
      got:      .word _DYNAMIC
                .word "struct link map address" */
-  gptr = (unsigned int *) desc[0];
   if (gptr[0] == 0xea9f1fdd                    /* b,l .-12,r20     */
       && gptr[1] == 0xd6801c1e                 /* depwi 0,31,2,r20 */
       && (ElfW(Addr)) gptr[2] == elf_machine_resolve ())