mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-22 13:00:06 +00:00
Fix [BZ 20098].
This commit is contained in:
parent
66cd050f26
commit
df3d455b23
@ -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.
|
||||
|
@ -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 ())
|
||||
|
Loading…
Reference in New Issue
Block a user