1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-08-08 17:42:12 +03:00

Fix ifunc support with DT_TEXTREL segments (BZ#20480)

Currently, DT_TEXTREL is incompatible with IFUNC.  When DT_TEXTREL or
DF_TEXTREL is seen, the dynamic linker calls __mprotect on the segments
with PROT_READ|PROT_WRITE before applying dynamic relocations. It leads
to segfault when performing IFUNC resolution (which requires PROT_EXEC
as well for the IFUNC resolver).

This patch makes it call __mprotect with extra PROT_WRITE bit, which
will keep the PROT_EXEC bit if exists, and thus fixes the segfault.
FreeBSD rtld libexec/rtld-elf/rtld.c (reloc_textrel_prot) does the same.

Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu,
sparc64-linux-gnu, sparcv9-linux-gnu, and armv8-linux-gnueabihf.

	Adam J. Richte  <adam_richter2004@yahoo.com>
	Adhemerval Zanella  <adhemerval.zanella@linaro.org>
	Fangrui Song  <maskray@google.com>

	[BZ #20480]
	* config.h.in (CAN_TEXTREL_IFUNC): New define.
	* configure.ac: Add check if linker supports textrel relocation with
	ifunc.
	* elf/dl-reloc.c (_dl_relocate_object): Use all required flags on
	DT_TEXTREL segments, not only PROT_READ and PROT_WRITE.
	* elf/Makefile (ifunc-pie-tests): Add tst-ifunc-textrel.
	(CFLAGS-tst-ifunc-textrel.c): New rule.
	* elf/tst-ifunc-textrel.c: New file.
This commit is contained in:
Adhemerval Zanella
2018-08-27 16:16:43 -03:00
parent d62f9ec0cc
commit b5c45e8375
7 changed files with 155 additions and 12 deletions

View File

@@ -200,17 +200,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
newp->start = PTR_ALIGN_DOWN (ph->p_vaddr, GLRO(dl_pagesize))
+ (caddr_t) l->l_addr;
if (__mprotect (newp->start, newp->len, PROT_READ|PROT_WRITE) < 0)
{
errstring = N_("cannot make segment writable for relocation");
call_error:
_dl_signal_error (errno, l->l_name, NULL, errstring);
}
#if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7
newp->prot = (PF_TO_PROT
>> ((ph->p_flags & (PF_R | PF_W | PF_X)) * 4)) & 0xf;
#else
newp->prot = 0;
if (ph->p_flags & PF_R)
newp->prot |= PROT_READ;
@@ -218,7 +207,14 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
newp->prot |= PROT_WRITE;
if (ph->p_flags & PF_X)
newp->prot |= PROT_EXEC;
#endif
if (__mprotect (newp->start, newp->len, newp->prot|PROT_WRITE) < 0)
{
errstring = N_("cannot make segment writable for relocation");
call_error:
_dl_signal_error (errno, l->l_name, NULL, errstring);
}
newp->next = textrels;
textrels = newp;
}