mirror of
https://sourceware.org/git/glibc.git
synced 2025-12-20 01:12:17 +08:00
elf: Support vDSO with more than one PT_LOAD with v_addr starting at 0 (BZ 32583)
The setup_vdso assumes that vDSO will contain only one PT_LOAD segment
and that 0 is the sentinel for the start mapping address. Although
the kernel avoids adding more than one PT_LOAD to avoid compatibility
issues, there is no impending issue that prevents glibc from supporting
vDSO with multiple PT_LOAD (as some wrapper tools do [1]).
To support multiple PT_LOAD segments, replace the sentinel with a bool
to indicate that the VMA start has already been set.
Testing is really tricky, since the bug report does not indicate which
tool was used to trigger the issue, nor a runtime that provides a vDSO
with multiple PT_LOAD. I had to modify the qemu user with a custom
script to create 2 PT_LOAD sections, remove checks that prevent the
vDSO object from being created, and remove the load bias adjustment
in load_elf_vdso. I could not come up with an easy test case to
integrate with glibc.
The Linux kernel provides vDSO with only one PT_LOAD due to
compatibility reasons. For instance
* arch/arm64/kernel/vdso/vdso.lds.S
86 /*
87 * We must supply the ELF program headers explicitly to get just one
88 * PT_LOAD segment, and set the flags explicitly to make segments read-only.
89 /
90 PHDRS
91 {
92 text PT_LOAD FLAGS(5) FILEHDR PHDRS; / PF_R|PF_X /
93 dynamic PT_DYNAMIC FLAGS(4); / PF_R /
94 note PT_NOTE FLAGS(4); / PF_R */
95 }
* arch/x86/entry/vdso/vdso-layout.lds.S
95 /*
96 * We must supply the ELF program headers explicitly to get just one
97 * PT_LOAD segment, and set the flags explicitly to make segments read-only.
98 /
99 PHDRS
100 {
101 text PT_LOAD FLAGS(5) FILEHDR PHDRS; / PF_R|PF_X /
102 dynamic PT_DYNAMIC FLAGS(4); / PF_R /
103 note PT_NOTE FLAGS(4); / PF_R */
104 eh_frame_hdr PT_GNU_EH_FRAME;
105 }
Checked on aarch64-linux-gnu.
[1] https://sourceware.org/bugzilla/show_bug.cgi?id=32583#c2
Reviewed-by: Florian Weimer <fweimer@redhat.com>
This commit is contained in:
@@ -31,6 +31,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
|
||||
mapped and relocated it normally. */
|
||||
struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL,
|
||||
__RTLD_VDSO, LM_ID_BASE);
|
||||
bool l_addr_set = false;
|
||||
if (__glibc_likely (l != NULL))
|
||||
{
|
||||
l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso)
|
||||
@@ -47,8 +48,11 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
|
||||
}
|
||||
else if (ph->p_type == PT_LOAD)
|
||||
{
|
||||
if (! l->l_addr)
|
||||
l->l_addr = ph->p_vaddr;
|
||||
if (!l_addr_set)
|
||||
{
|
||||
l->l_addr = ph->p_vaddr;
|
||||
l_addr_set = true;
|
||||
}
|
||||
if (ph->p_vaddr + ph->p_memsz >= l->l_map_end)
|
||||
l->l_map_end = ph->p_vaddr + ph->p_memsz;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user