diff mbox series

[05/12] elf: switch _dl_map_segment() to anonymous mapping

Message ID 20230403090421.560208-6-stsp2@yandex.ru
State New
Headers show
Series implement dlmem() function | expand

Commit Message

stsp April 3, 2023, 9:04 a.m. UTC
_dl_map_segment() was mapping entire file image and then was skipping
the load of the first segment. Switch _dl_map_segment() to anonymous
mapping and do not skip the map of the first segment.

Use PROT_READ|PROT_WRITE as a protection. _dl_map_segments() later
sets the proper protection for both file-mapped and anonymous parts.

The test-suite was run on x86_64/64 and showed no regressions.

Signed-off-by: Stas Sergeev <stsp2@yandex.ru>
---
 elf/dl-map-segments.h | 69 ++++++++++++++++++++++---------------------
 1 file changed, 35 insertions(+), 34 deletions(-)
diff mbox series

Patch

diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h
index 504cfc0a41..ed7675cabf 100644
--- a/elf/dl-map-segments.h
+++ b/elf/dl-map-segments.h
@@ -22,18 +22,22 @@ 
 /* Map a segment and align it properly.  */
 
 static __always_inline ElfW(Addr)
-_dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref,
-		 const size_t maplength, int fd)
+_dl_map_segment (ElfW(Addr) mappref, size_t maplength, size_t mapalign)
 {
-  if (__glibc_likely (c->mapalign <= GLRO(dl_pagesize)))
-    return (ElfW(Addr)) __mmap ((void *) mappref, maplength, c->prot,
-				MAP_COPY|MAP_FILE, fd, c->mapoff);
+  int err;
+  /* MAP_COPY is a special flag combination for solibs. */
+  unsigned int map_flags = MAP_ANONYMOUS | MAP_COPY;
+  unsigned int prot = PROT_READ | PROT_WRITE;
+
+  if (__glibc_likely (mapalign <= GLRO(dl_pagesize)))
+    return (ElfW(Addr)) __mmap ((void *) mappref, maplength, prot,
+				map_flags, -1, 0);
 
   /* If the segment alignment > the page size, allocate enough space to
      ensure that the segment can be properly aligned.  */
-  ElfW(Addr) maplen = (maplength >= c->mapalign
-		       ? (maplength + c->mapalign)
-		       : (2 * c->mapalign));
+  ElfW(Addr) maplen = (maplength >= mapalign
+		       ? (maplength + mapalign)
+		       : (2 * mapalign));
   ElfW(Addr) map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplen,
 					      PROT_NONE,
 					      MAP_ANONYMOUS|MAP_PRIVATE,
@@ -41,26 +45,24 @@  _dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref,
   if (__glibc_unlikely ((void *) map_start == MAP_FAILED))
     return map_start;
 
-  ElfW(Addr) map_start_aligned = ALIGN_UP (map_start, c->mapalign);
-  map_start_aligned = (ElfW(Addr)) __mmap ((void *) map_start_aligned,
-					   maplength, c->prot,
-					   MAP_COPY|MAP_FILE|MAP_FIXED,
-					   fd, c->mapoff);
-  if (__glibc_unlikely ((void *) map_start_aligned == MAP_FAILED))
-    __munmap ((void *) map_start, maplen);
-  else
+  ElfW(Addr) map_start_aligned = ALIGN_UP (map_start, mapalign);
+  err = __mprotect ((void *) map_start_aligned, maplength, prot);
+  if (__glibc_unlikely (err))
     {
-      /* Unmap the unused regions.  */
-      ElfW(Addr) delta = map_start_aligned - map_start;
-      if (delta)
-	__munmap ((void *) map_start, delta);
-      ElfW(Addr) map_end = map_start_aligned + maplength;
-      map_end = ALIGN_UP (map_end, GLRO(dl_pagesize));
-      delta = map_start + maplen - map_end;
-      if (delta)
-	__munmap ((void *) map_end, delta);
+      __munmap ((void *) map_start, maplen);
+      return (ElfW(Addr)) MAP_FAILED;
     }
 
+  /* Unmap the unused regions.  */
+  ElfW(Addr) delta = map_start_aligned - map_start;
+  if (delta)
+    __munmap ((void *) map_start, delta);
+  ElfW(Addr) map_end = map_start_aligned + maplength;
+  map_end = ALIGN_UP (map_end, GLRO(dl_pagesize));
+  delta = map_start + maplen - map_end;
+  if (delta)
+    __munmap ((void *) map_end, delta);
+
   return map_start_aligned;
 }
 
@@ -98,7 +100,7 @@  _dl_map_segments (struct link_map *l, int fd,
            - MAP_BASE_ADDR (l));
 
       /* Remember which part of the address space this object uses.  */
-      l->l_map_start = _dl_map_segment (c, mappref, maplength, fd);
+      l->l_map_start = _dl_map_segment (mappref, maplength, c->mapalign);
       if (__glibc_unlikely ((void *) l->l_map_start == MAP_FAILED))
         return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;
 
@@ -123,14 +125,14 @@  _dl_map_segments (struct link_map *l, int fd,
         }
 
       l->l_contiguous = 1;
-
-      goto postmap;
     }
-
-  /* Remember which part of the address space this object uses.  */
-  l->l_map_start = c->mapstart + l->l_addr;
-  l->l_map_end = l->l_map_start + maplength;
-  l->l_contiguous = !has_holes;
+  else
+    {
+      /* Remember which part of the address space this object uses.  */
+      l->l_map_start = c->mapstart + l->l_addr;
+      l->l_map_end = l->l_map_start + maplength;
+      l->l_contiguous = !has_holes;
+    }
 
   while (c < &loadcmds[nloadcmds])
     {
@@ -143,7 +145,6 @@  _dl_map_segments (struct link_map *l, int fd,
               == MAP_FAILED))
         return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;
 
-    postmap:
       _dl_postprocess_loadcmd (l, header, c);
 
       if (c->allocend > c->dataend)