mirror of
https://sourceware.org/git/glibc.git
synced 2025-07-29 11:41:21 +03:00
Fix [BZ 20098].
This commit is contained in:
@ -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>
|
2017-07-16 Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||||||
|
|
||||||
* po/libc.pot: Regenerate.
|
* po/libc.pot: Regenerate.
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <dl-fptr.h>
|
#include <dl-fptr.h>
|
||||||
#include <dl-unmap-segments.h>
|
#include <dl-unmap-segments.h>
|
||||||
#include <atomic.h>
|
#include <atomic.h>
|
||||||
|
#include <libc-pointer-arith.h>
|
||||||
|
|
||||||
#ifndef ELF_MACHINE_BOOT_FPTR_TABLE_LEN
|
#ifndef ELF_MACHINE_BOOT_FPTR_TABLE_LEN
|
||||||
/* ELF_MACHINE_BOOT_FPTR_TABLE_LEN should be greater than the number of
|
/* 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))
|
static inline ElfW(Addr) * __attribute__ ((always_inline))
|
||||||
make_fptr_table (struct link_map *map)
|
make_fptr_table (struct link_map *map)
|
||||||
{
|
{
|
||||||
const ElfW(Sym) *symtab
|
const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
|
||||||
= (const void *) D_PTR (map, l_info[DT_SYMTAB]);
|
|
||||||
const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
|
const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
|
||||||
ElfW(Addr) *fptr_table;
|
ElfW(Addr) *fptr_table;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
const ElfW(Sym) *symtabend;
|
||||||
|
|
||||||
/* XXX Apparently the only way to find out the size of the dynamic
|
/* Determine the end of the dynamic symbol table using the hash. */
|
||||||
symbol section is to assume that the string table follows right
|
if (map->l_info[DT_HASH] != NULL)
|
||||||
afterwards... */
|
symtabend = (symtab + ((Elf_Symndx *) D_PTR (map, l_info[DT_HASH]))[1]);
|
||||||
len = ((strtab - (char *) symtab)
|
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);
|
/ map->l_info[DT_SYMENT]->d_un.d_val);
|
||||||
size = ((len * sizeof (fptr_table[0]) + GLRO(dl_pagesize) - 1)
|
size = ALIGN_UP (len * sizeof (fptr_table[0]), GLRO(dl_pagesize));
|
||||||
& -GLRO(dl_pagesize));
|
|
||||||
/* XXX We don't support here in the moment systems without MAP_ANON.
|
/* We don't support systems without MAP_ANON. We avoid using malloc
|
||||||
There probably are none for IA-64. In case this is proven wrong
|
because this might get called before malloc is setup. */
|
||||||
we will have to open /dev/null here and use the file descriptor
|
|
||||||
instead of the hard-coded -1. */
|
|
||||||
fptr_table = __mmap (NULL, size,
|
fptr_table = __mmap (NULL, size,
|
||||||
PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
|
PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
|
||||||
-1, 0);
|
-1, 0);
|
||||||
@ -331,22 +337,45 @@ elf_machine_resolve (void)
|
|||||||
return addr;
|
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)
|
ElfW(Addr)
|
||||||
_dl_lookup_address (const void *address)
|
_dl_lookup_address (const void *address)
|
||||||
{
|
{
|
||||||
ElfW(Addr) addr = (ElfW(Addr)) address;
|
ElfW(Addr) addr = (ElfW(Addr)) address;
|
||||||
unsigned int *desc, *gptr;
|
unsigned int *desc, *gptr;
|
||||||
|
|
||||||
/* Check for special cases. */
|
/* Return ADDR if the least-significant two bits of ADDR are not consistent
|
||||||
if ((int) addr == -1
|
with ADDR being a linker defined function pointer. The normal value for
|
||||||
|| (unsigned int) addr < 4096
|
a code address in a backtrace is 3. */
|
||||||
|| !((unsigned int) addr & 2))
|
if (((unsigned int) addr & 3) != 2)
|
||||||
|
return addr;
|
||||||
|
|
||||||
|
/* Handle special case where ADDR points to page 0. */
|
||||||
|
if ((unsigned int) addr < 4096)
|
||||||
return addr;
|
return addr;
|
||||||
|
|
||||||
/* Clear least-significant two bits from descriptor address. */
|
/* Clear least-significant two bits from descriptor address. */
|
||||||
desc = (unsigned int *) ((unsigned int) addr & ~3);
|
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:
|
used in each global offset table for function resolution:
|
||||||
|
|
||||||
ldw 0(r20),r22
|
ldw 0(r20),r22
|
||||||
@ -358,7 +387,6 @@ _dl_lookup_address (const void *address)
|
|||||||
.word "_dl_runtime_resolve ltp"
|
.word "_dl_runtime_resolve ltp"
|
||||||
got: .word _DYNAMIC
|
got: .word _DYNAMIC
|
||||||
.word "struct link map address" */
|
.word "struct link map address" */
|
||||||
gptr = (unsigned int *) desc[0];
|
|
||||||
if (gptr[0] == 0xea9f1fdd /* b,l .-12,r20 */
|
if (gptr[0] == 0xea9f1fdd /* b,l .-12,r20 */
|
||||||
&& gptr[1] == 0xd6801c1e /* depwi 0,31,2,r20 */
|
&& gptr[1] == 0xd6801c1e /* depwi 0,31,2,r20 */
|
||||||
&& (ElfW(Addr)) gptr[2] == elf_machine_resolve ())
|
&& (ElfW(Addr)) gptr[2] == elf_machine_resolve ())
|
||||||
|
Reference in New Issue
Block a user