Blame elf/dl-map-segments.h

Packit Service 82fcde
/* Map in a shared object's segments.  Generic version.
Packit Service 82fcde
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <dl-load.h>
Packit Service 82fcde
Packit Service 82fcde
/* This implementation assumes (as does the corresponding implementation
Packit Service 82fcde
   of _dl_unmap_segments, in dl-unmap-segments.h) that shared objects
Packit Service 82fcde
   are always laid out with all segments contiguous (or with gaps
Packit Service 82fcde
   between them small enough that it's preferable to reserve all whole
Packit Service 82fcde
   pages inside the gaps with PROT_NONE mappings rather than permitting
Packit Service 82fcde
   other use of those parts of the address space).  */
Packit Service 82fcde
Packit Service 82fcde
static __always_inline const char *
Packit Service 82fcde
_dl_map_segments (struct link_map *l, int fd,
Packit Service 82fcde
                  const ElfW(Ehdr) *header, int type,
Packit Service 82fcde
                  const struct loadcmd loadcmds[], size_t nloadcmds,
Packit Service 82fcde
                  const size_t maplength, bool has_holes,
Packit Service 82fcde
                  struct link_map *loader)
Packit Service 82fcde
{
Packit Service 82fcde
  const struct loadcmd *c = loadcmds;
Packit Service 82fcde
Packit Service 82fcde
  if (__glibc_likely (type == ET_DYN))
Packit Service 82fcde
    {
Packit Service 82fcde
      /* This is a position-independent shared object.  We can let the
Packit Service 82fcde
         kernel map it anywhere it likes, but we must have space for all
Packit Service 82fcde
         the segments in their specified positions relative to the first.
Packit Service 82fcde
         So we map the first segment without MAP_FIXED, but with its
Packit Service 82fcde
         extent increased to cover all the segments.  Then we remove
Packit Service 82fcde
         access from excess portion, and there is known sufficient space
Packit Service 82fcde
         there to remap from the later segments.
Packit Service 82fcde
Packit Service 82fcde
         As a refinement, sometimes we have an address that we would
Packit Service 82fcde
         prefer to map such objects at; but this is only a preference,
Packit Service 82fcde
         the OS can do whatever it likes. */
Packit Service 82fcde
      ElfW(Addr) mappref
Packit Service 82fcde
        = (ELF_PREFERRED_ADDRESS (loader, maplength,
Packit Service 82fcde
                                  c->mapstart & GLRO(dl_use_load_bias))
Packit Service 82fcde
           - MAP_BASE_ADDR (l));
Packit Service 82fcde
Packit Service 82fcde
      /* Remember which part of the address space this object uses.  */
Packit Service 82fcde
      l->l_map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplength,
Packit Service 82fcde
                                            c->prot,
Packit Service 82fcde
                                            MAP_COPY|MAP_FILE,
Packit Service 82fcde
                                            fd, c->mapoff);
Packit Service 82fcde
      if (__glibc_unlikely ((void *) l->l_map_start == MAP_FAILED))
Packit Service 82fcde
        return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;
Packit Service 82fcde
Packit Service 82fcde
      l->l_map_end = l->l_map_start + maplength;
Packit Service 82fcde
      l->l_addr = l->l_map_start - c->mapstart;
Packit Service 82fcde
Packit Service 82fcde
      if (has_holes)
Packit Service 82fcde
        {
Packit Service 82fcde
          /* Change protection on the excess portion to disallow all access;
Packit Service 82fcde
             the portions we do not remap later will be inaccessible as if
Packit Service 82fcde
             unallocated.  Then jump into the normal segment-mapping loop to
Packit Service 82fcde
             handle the portion of the segment past the end of the file
Packit Service 82fcde
             mapping.  */
Packit Service 82fcde
          if (__glibc_unlikely
Packit Service 82fcde
              (__mprotect ((caddr_t) (l->l_addr + c->mapend),
Packit Service 82fcde
                           loadcmds[nloadcmds - 1].mapstart - c->mapend,
Packit Service 82fcde
                           PROT_NONE) < 0))
Packit Service 82fcde
            return DL_MAP_SEGMENTS_ERROR_MPROTECT;
Packit Service 82fcde
        }
Packit Service 82fcde
Packit Service 82fcde
      l->l_contiguous = 1;
Packit Service 82fcde
Packit Service 82fcde
      goto postmap;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Remember which part of the address space this object uses.  */
Packit Service 82fcde
  l->l_map_start = c->mapstart + l->l_addr;
Packit Service 82fcde
  l->l_map_end = l->l_map_start + maplength;
Packit Service 82fcde
  l->l_contiguous = !has_holes;
Packit Service 82fcde
Packit Service 82fcde
  while (c < &loadcmds[nloadcmds])
Packit Service 82fcde
    {
Packit Service 82fcde
      if (c->mapend > c->mapstart
Packit Service 82fcde
          /* Map the segment contents from the file.  */
Packit Service 82fcde
          && (__mmap ((void *) (l->l_addr + c->mapstart),
Packit Service 82fcde
                      c->mapend - c->mapstart, c->prot,
Packit Service 82fcde
                      MAP_FIXED|MAP_COPY|MAP_FILE,
Packit Service 82fcde
                      fd, c->mapoff)
Packit Service 82fcde
              == MAP_FAILED))
Packit Service 82fcde
        return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;
Packit Service 82fcde
Packit Service 82fcde
    postmap:
Packit Service 82fcde
      _dl_postprocess_loadcmd (l, header, c);
Packit Service 82fcde
Packit Service 82fcde
      if (c->allocend > c->dataend)
Packit Service 82fcde
        {
Packit Service 82fcde
          /* Extra zero pages should appear at the end of this segment,
Packit Service 82fcde
             after the data mapped from the file.   */
Packit Service 82fcde
          ElfW(Addr) zero, zeroend, zeropage;
Packit Service 82fcde
Packit Service 82fcde
          zero = l->l_addr + c->dataend;
Packit Service 82fcde
          zeroend = l->l_addr + c->allocend;
Packit Service 82fcde
          zeropage = ((zero + GLRO(dl_pagesize) - 1)
Packit Service 82fcde
                      & ~(GLRO(dl_pagesize) - 1));
Packit Service 82fcde
Packit Service 82fcde
          if (zeroend < zeropage)
Packit Service 82fcde
            /* All the extra data is in the last page of the segment.
Packit Service 82fcde
               We can just zero it.  */
Packit Service 82fcde
            zeropage = zeroend;
Packit Service 82fcde
Packit Service 82fcde
          if (zeropage > zero)
Packit Service 82fcde
            {
Packit Service 82fcde
              /* Zero the final part of the last page of the segment.  */
Packit Service 82fcde
              if (__glibc_unlikely ((c->prot & PROT_WRITE) == 0))
Packit Service 82fcde
                {
Packit Service 82fcde
                  /* Dag nab it.  */
Packit Service 82fcde
                  if (__mprotect ((caddr_t) (zero
Packit Service 82fcde
                                             & ~(GLRO(dl_pagesize) - 1)),
Packit Service 82fcde
                                  GLRO(dl_pagesize), c->prot|PROT_WRITE) < 0)
Packit Service 82fcde
                    return DL_MAP_SEGMENTS_ERROR_MPROTECT;
Packit Service 82fcde
                }
Packit Service 82fcde
              memset ((void *) zero, '\0', zeropage - zero);
Packit Service 82fcde
              if (__glibc_unlikely ((c->prot & PROT_WRITE) == 0))
Packit Service 82fcde
                __mprotect ((caddr_t) (zero & ~(GLRO(dl_pagesize) - 1)),
Packit Service 82fcde
                            GLRO(dl_pagesize), c->prot);
Packit Service 82fcde
            }
Packit Service 82fcde
Packit Service 82fcde
          if (zeroend > zeropage)
Packit Service 82fcde
            {
Packit Service 82fcde
              /* Map the remaining zero pages in from the zero fill FD.  */
Packit Service 82fcde
              caddr_t mapat;
Packit Service 82fcde
              mapat = __mmap ((caddr_t) zeropage, zeroend - zeropage,
Packit Service 82fcde
                              c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED,
Packit Service 82fcde
                              -1, 0);
Packit Service 82fcde
              if (__glibc_unlikely (mapat == MAP_FAILED))
Packit Service 82fcde
                return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL;
Packit Service 82fcde
            }
Packit Service 82fcde
        }
Packit Service 82fcde
Packit Service 82fcde
      ++c;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Notify ELF_PREFERRED_ADDRESS that we have to load this one
Packit Service 82fcde
     fixed.  */
Packit Service 82fcde
  ELF_FIXED_ADDRESS (loader, c->mapstart);
Packit Service 82fcde
Packit Service 82fcde
  return NULL;
Packit Service 82fcde
}