Fix [BZ 20098].

This commit is contained in:
John David Anglin 2017-07-16 10:51:13 -04:00
parent 66cd050f26
commit df3d455b23
2 changed files with 54 additions and 18 deletions

View File

@ -1,3 +1,11 @@
2017-07-16 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.
2017-07-16 Siddhesh Poyarekar <siddhesh@sourceware.org>
* po/libc.pot: Regenerate.

View File

@ -28,6 +28,7 @@
#include <dl-fptr.h>
#include <dl-unmap-segments.h>
#include <atomic.h>
#include <libc-pointer-arith.h>
#ifndef ELF_MACHINE_BOOT_FPTR_TABLE_LEN
/* ELF_MACHINE_BOOT_FPTR_TABLE_LEN should be greater than the number of
@ -181,24 +182,29 @@ make_fdesc (ElfW(Addr) ip, ElfW(Addr) gp)
static inline ElfW(Addr) * __attribute__ ((always_inline))
make_fptr_table (struct link_map *map)
{
const ElfW(Sym) *symtab
= (const void *) D_PTR (map, l_info[DT_SYMTAB]);
const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
ElfW(Addr) *fptr_table;
size_t size;
size_t len;
const ElfW(Sym) *symtabend;
/* XXX Apparently the only way to find out the size of the dynamic
symbol section is to assume that the string table follows right
afterwards... */
len = ((strtab - (char *) symtab)
/* Determine the end of the dynamic symbol table using the hash. */
if (map->l_info[DT_HASH] != NULL)
symtabend = (symtab + ((Elf_Symndx *) D_PTR (map, l_info[DT_HASH]))[1]);
else
/* There is no direct way to determine the number of symbols in the
dynamic symbol table and no hash table is present. The ELF
binary is ill-formed but what shall we do? Use the beginning of
the string table which generally follows the symbol table. */
symtabend = (const ElfW(Sym) *) strtab;
len = (((char *) symtabend - (char *) symtab)
/ map->l_info[DT_SYMENT]->d_un.d_val);
size = ((len * sizeof (fptr_table[0]) + GLRO(dl_pagesize) - 1)
& -GLRO(dl_pagesize));
/* XXX We don't support here in the moment systems without MAP_ANON.
There probably are none for IA-64. In case this is proven wrong
we will have to open /dev/null here and use the file descriptor
instead of the hard-coded -1. */
size = ALIGN_UP (len * sizeof (fptr_table[0]), GLRO(dl_pagesize));
/* We don't support systems without MAP_ANON. We avoid using malloc
because this might get called before malloc is setup. */
fptr_table = __mmap (NULL, size,
PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
-1, 0);
@ -331,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;
/* Check if descriptor requires resolution. The following trampoline is
/* 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;
/* See if descriptor requires resolution. The following trampoline is
used in each global offset table for function resolution:
ldw 0(r20),r22
@ -358,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 ())