From: Adhemerval Zanella Date: Tue, 9 Dec 2025 21:35:13 +0000 (-0300) Subject: elf: Support vDSO with more than one PT_LOAD with v_addr starting at 0 (BZ 32583) X-Git-Tag: glibc-2.43~69 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9021707ca79ce6f421f29a189630df860598cf15;p=thirdparty%2Fglibc.git 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 --- diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h index 935d9e3baf..6e974875e7 100644 --- a/elf/setup-vdso.h +++ b/elf/setup-vdso.h @@ -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; }