2016-05-14 John David Anglin [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 ())