aboutsummaryrefslogtreecommitdiff
path: root/elf/rtld.c
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2024-07-02 13:19:13 +0200
committerFlorian Weimer <fweimer@redhat.com>2024-07-08 15:28:00 +0200
commita2f53a77559b610c8bf762c5d22172d9d45800e0 (patch)
treebe4fbd7a144bcb5840be71d09ef117a55794f41a /elf/rtld.c
parent9fc639f654dc004736836613be703e6bed0c36a8 (diff)
downloadglibc-fw/bug31943-with-test.tar.xz
glibc-fw/bug31943-with-test.zip
elf: Handle ld.so with LOAD segment gaps in _dl_find_object (bug 31943)fw/bug31943-with-test
Diffstat (limited to 'elf/rtld.c')
-rw-r--r--elf/rtld.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/elf/rtld.c b/elf/rtld.c
index bfdf632e77..337901007d 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1766,6 +1766,30 @@ dl_main (const ElfW(Phdr) *phdr,
GL(dl_rtld_map).l_phdr = rtld_phdr;
GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
+ GL(dl_rtld_map).l_contiguous = 1;
+#ifdef HAVE_LD_LOAD_GAPS
+ /* The linker may not have produced a contiguous object. The kernel
+ will load the object with actual gaps (unlike the glibc loader
+ for shared objects, which always produces a contiguous mapping).
+ See similar logic in rtld_setup_main_map. */
+ {
+ ElfW(Addr) expected_load_address = 0;
+ for (const ElfW(Phdr) *ph = rtld_phdr; ph < &phdr[rtld_ehdr->e_phnum];
+ ++ph)
+ if (ph->p_type == PT_LOAD)
+ {
+ ElfW(Addr) mapstart = ph->p_vaddr & ~(GLRO(dl_pagesize) - 1);
+ if (GL(dl_rtld_map).l_contiguous && expected_load_address != 0
+ && expected_load_address != mapstart)
+ GL(dl_rtld_map).l_contiguous = 0;
+ ElfW(Addr) allocend = ph->p_vaddr + ph->p_memsz;
+ /* The next expected address is the page following this load
+ segment. */
+ expected_load_address = ((allocend + GLRO(dl_pagesize) - 1)
+ & ~(GLRO(dl_pagesize) - 1));
+ }
+ }
+#endif
/* PT_GNU_RELRO is usually the last phdr. */