1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
|
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.
diff --git a/sysdeps/hppa/dl-fptr.c b/sysdeps/hppa/dl-fptr.c
index 083242b..af0c5a1 100644
--- a/sysdeps/hppa/dl-fptr.c
+++ b/sysdeps/hppa/dl-fptr.c
@@ -331,22 +331,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
@@ -358,7 +381,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 ())
|