Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/libexec/ld.elf_so Remove the limitation of only being able t...



details:   https://anonhg.NetBSD.org/src/rev/e22f04309719
branches:  trunk
changeset: 372934:e22f04309719
user:      christos <christos%NetBSD.org@localhost>
date:      Fri Jan 06 15:33:47 2023 +0000

description:
Remove the limitation of only being able to load binaries with 2 PT_LOAD
sections, like the kernel can. From FreeBSD.

diffstat:

 libexec/ld.elf_so/map_object.c |  276 ++++++++++++++++++++++------------------
 1 files changed, 154 insertions(+), 122 deletions(-)

diffs (truncated from 475 to 300 lines):

diff -r e08ee8d7646d -r e22f04309719 libexec/ld.elf_so/map_object.c
--- a/libexec/ld.elf_so/map_object.c    Fri Jan 06 15:07:22 2023 +0000
+++ b/libexec/ld.elf_so/map_object.c    Fri Jan 06 15:33:47 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: map_object.c,v 1.62 2022/03/30 08:26:45 hannken Exp $   */
+/*     $NetBSD: map_object.c,v 1.63 2023/01/06 15:33:47 christos Exp $  */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -34,7 +34,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: map_object.c,v 1.62 2022/03/30 08:26:45 hannken Exp $");
+__RCSID("$NetBSD: map_object.c,v 1.63 2023/01/06 15:33:47 christos Exp $");
 #endif /* not lint */
 
 #include <errno.h>
@@ -49,7 +49,8 @@
 #include "debug.h"
 #include "rtld.h"
 
-static int protflags(int);     /* Elf flags -> mmap protection */
+static int convert_prot(int);  /* Elf flags -> mmap protection */
+static int convert_flags(int);  /* Elf flags -> mmap flags */
 
 #define EA_UNDEF               (~(Elf_Addr)0)
 
@@ -69,35 +70,35 @@
 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
        Elf_Phdr        *phtls;
 #endif
-       size_t           phsize;
        Elf_Phdr        *phlimit;
-       Elf_Phdr        *segs[2];
+       Elf_Phdr       **segs = NULL;
        int              nsegs;
        caddr_t          mapbase = MAP_FAILED;
        size_t           mapsize = 0;
        int              mapflags;
-       Elf_Off          base_offset;
        Elf_Addr         base_alignment;
        Elf_Addr         base_vaddr;
        Elf_Addr         base_vlimit;
        Elf_Addr         text_vlimit;
-       int              text_flags;
+       Elf_Addr         text_end;
        void            *base_addr;
        Elf_Off          data_offset;
        Elf_Addr         data_vaddr;
        Elf_Addr         data_vlimit;
        int              data_flags;
+       int              data_prot;
        caddr_t          data_addr;
+       Elf_Addr         bss_vaddr;
+       Elf_Addr         bss_vlimit;
+       caddr_t          bss_addr;
 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
        Elf_Addr         tls_vaddr = 0; /* Noise GCC */
 #endif
        Elf_Addr         phdr_vaddr;
-       size_t           phdr_memsz;
-       caddr_t          gap_addr;
-       size_t           gap_size;
        int i;
 #ifdef RTLD_LOADER
        Elf_Addr         clear_vaddr;
+       caddr_t          clear_page;
        caddr_t          clear_addr;
        size_t           nclear;
 #endif
@@ -105,6 +106,9 @@
        Elf_Addr         relro_page;
        size_t           relro_size;
 #endif
+#ifdef notyet
+       int              stack_flags;
+#endif
 
        if (sb != NULL && sb->st_size < (off_t)sizeof (Elf_Ehdr)) {
                _rtld_error("%s: not ELF file (too short)", path);
@@ -124,34 +128,34 @@
        obj->ehdr = ehdr;
        if (ehdr == MAP_FAILED) {
                _rtld_error("%s: read error: %s", path, xstrerror(errno));
-               goto bad;
+               goto error;
        }
        /* Make sure the file is valid */
        if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0) {
                _rtld_error("%s: not ELF file (magic number bad)", path);
-               goto bad;
+               goto error;
        }
        if (ehdr->e_ident[EI_CLASS] != ELFCLASS) {
                _rtld_error("%s: invalid ELF class %x; expected %x", path,
                    ehdr->e_ident[EI_CLASS], ELFCLASS);
-               goto bad;
+               goto error;
        }
        /* Elf_e_ident includes class */
        if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
            ehdr->e_version != EV_CURRENT ||
            ehdr->e_ident[EI_DATA] != ELFDEFNNAME(MACHDEP_ENDIANNESS)) {
                _rtld_error("%s: unsupported file version", path);
-               goto bad;
+               goto error;
        }
        if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
                _rtld_error("%s: unsupported file type", path);
-               goto bad;
+               goto error;
        }
        switch (ehdr->e_machine) {
                ELFDEFNNAME(MACHDEP_ID_CASES)
        default:
                _rtld_error("%s: unsupported machine", path);
-               goto bad;
+               goto error;
        }
 
        /*
@@ -173,16 +177,22 @@
 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
        phtls = NULL;
 #endif
-       phsize = ehdr->e_phnum * sizeof(phdr[0]);
        obj->phdr = NULL;
 #ifdef GNU_RELRO
        relro_page = 0;
        relro_size = 0;
 #endif
        phdr_vaddr = EA_UNDEF;
-       phdr_memsz = 0;
        phlimit = phdr + ehdr->e_phnum;
-       nsegs = 0;
+       segs = xmalloc(sizeof(segs[0]) * ehdr->e_phnum);
+       if (segs == NULL) {
+               _rtld_error("No memory for segs");
+               goto error;
+       }
+#ifdef notyet
+       stack_flags = PF_R | PF_W;
+#endif
+       nsegs = -1;
        while (phdr < phlimit) {
                switch (phdr->p_type) {
                case PT_INTERP:
@@ -191,21 +201,37 @@
                        break;
 
                case PT_LOAD:
-                       if (nsegs < 2)
-                               segs[nsegs] = phdr;
-                       ++nsegs;
+                       segs[++nsegs] = phdr;
+                       if ((segs[nsegs]->p_align & (_rtld_pagesz - 1)) != 0) {
+                               _rtld_error(
+                                   "%s: PT_LOAD segment %d not page-aligned",
+                                   path, nsegs);
+                               goto error;
+                       }
+                       if ((segs[nsegs]->p_flags & PF_X) == PF_X) {
+                               text_end = MAX(text_end,
+                                   round_up(segs[nsegs]->p_vaddr +
+                                   segs[nsegs]->p_memsz));
+                       }
 
-                       dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_LOAD",
+                       dbg(("%s: %s %p phsize %" PRImemsz, obj->path,
+                           "PT_LOAD",
                            (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
                        break;
 
                case PT_PHDR:
                        phdr_vaddr = phdr->p_vaddr;
-                       phdr_memsz = phdr->p_memsz;
-                       dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_PHDR",
+                       dbg(("%s: %s %p phsize %" PRImemsz, obj->path,
+                           "PT_PHDR",
                            (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
                        break;
 
+#ifdef notyet
+               case PT_GNU_STACK:
+                       stack_flags = phdr->p_flags;
+                       break;
+#endif
+
 #ifdef GNU_RELRO
                case PT_GNU_RELRO:
                        relro_page = phdr->p_vaddr;
@@ -215,7 +241,8 @@
 
                case PT_DYNAMIC:
                        obj->dynamic = (void *)(uintptr_t)phdr->p_vaddr;
-                       dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_DYNAMIC",
+                       dbg(("%s: %s %p phsize %" PRImemsz, obj->path,
+                           "PT_DYNAMIC",
                            (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
                        break;
 
@@ -240,12 +267,7 @@
        obj->entry = (void *)(uintptr_t)ehdr->e_entry;
        if (!obj->dynamic) {
                _rtld_error("%s: not dynamically linked", path);
-               goto bad;
-       }
-       if (nsegs != 2) {
-               _rtld_error("%s: wrong number of segments (%d != 2)", path,
-                   nsegs);
-               goto bad;
+               goto error;
        }
 
        /*
@@ -261,17 +283,15 @@
         */
 
        base_alignment = segs[0]->p_align;
-       base_offset = round_down(segs[0]->p_offset);
        base_vaddr = round_down(segs[0]->p_vaddr);
-       base_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_memsz);
+       base_vlimit = round_up(segs[nsegs]->p_vaddr + segs[nsegs]->p_memsz);
        text_vlimit = round_up(segs[0]->p_vaddr + segs[0]->p_memsz);
-       text_flags = protflags(segs[0]->p_flags);
-       data_offset = round_down(segs[1]->p_offset);
-       data_vaddr = round_down(segs[1]->p_vaddr);
-       data_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_filesz);
-       data_flags = protflags(segs[1]->p_flags);
+       data_offset = round_down(segs[nsegs]->p_offset);
+       data_vaddr = round_down(segs[nsegs]->p_vaddr);
+       data_vlimit = round_up(segs[nsegs]->p_vaddr + segs[nsegs]->p_filesz);
+       data_flags = convert_prot(segs[nsegs]->p_flags);
 #ifdef RTLD_LOADER
-       clear_vaddr = segs[1]->p_vaddr + segs[1]->p_filesz;
+       clear_vaddr = segs[nsegs]->p_vaddr + segs[nsegs]->p_filesz;
 #endif
 
        obj->textsize = text_vlimit - base_vaddr;
@@ -289,54 +309,15 @@
        }
 #endif
 
-       obj->phdr_loaded = false;
-       for (i = 0; i < nsegs; i++) {
-               if (phdr_vaddr != EA_UNDEF &&
-                   segs[i]->p_vaddr <= phdr_vaddr &&
-                   segs[i]->p_memsz >= phdr_memsz) {
-                       obj->phdr_loaded = true;
-                       break;
-               }
-               if (segs[i]->p_offset <= ehdr->e_phoff &&
-                   segs[i]->p_memsz >= phsize) {
-                       phdr_vaddr = segs[i]->p_vaddr + ehdr->e_phoff;
-                       phdr_memsz = phsize;
-                       obj->phdr_loaded = true;
-                       break;
-               }
-       }
-       if (obj->phdr_loaded) {
-               obj->phdr = (void *)(uintptr_t)phdr_vaddr;
-               obj->phsize = phdr_memsz;
-       } else {
-               Elf_Phdr *buf;
-               buf = xmalloc(phsize);
-               if (buf == NULL) {
-                       _rtld_error("%s: cannot allocate program header", path);
-                       goto bad;
-               }
-               memcpy(buf, phdr, phsize);
-               obj->phdr = buf;
-               obj->phsize = phsize;
-       }
-       dbg(("%s: phdr %p phsize %zu (%s)", obj->path, obj->phdr, obj->phsize,
-            obj->phdr_loaded ? "loaded" : "allocated"));
-
-       /* Unmap header if it overlaps the first load section. */
-       if (base_offset < _rtld_pagesz) {
-               munmap(ehdr, _rtld_pagesz);
-               obj->ehdr = MAP_FAILED;
-       }
-
        /*
         * Calculate log2 of the base section alignment.
         */
-       mapflags = 0;
+       mapflags = MAP_PRIVATE | MAP_ANON;
        if (base_alignment > _rtld_pagesz) {
                unsigned int log2 = 0;
                for (; base_alignment > 1; base_alignment >>= 1)
                        log2++;
-               mapflags = MAP_ALIGNED(log2);
+               mapflags |= MAP_ALIGNED(log2);
        }
 
        base_addr = NULL;
@@ -347,57 +328,90 @@
        }
 #endif



Home | Main Index | Thread Index | Old Index