public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
From: Stas Sergeev <stsp2@yandex.ru>
To: libc-alpha@sourceware.org
Cc: Stas Sergeev <stsp2@yandex.ru>
Subject: [PATCH 13/13] dlfcn,elf: impl DLMEM_DONTREPLACE dlmem() flag
Date: Sat, 18 Mar 2023 21:51:10 +0500	[thread overview]
Message-ID: <20230318165110.3672749-14-stsp2@yandex.ru> (raw)
In-Reply-To: <20230318165110.3672749-1-stsp2@yandex.ru>

This flag preserves the destination mapping by using memcpy()
from the source buffer. It is useful if the backing-store was
mapped with MAP_SHARED.

This patch adds a test-case named tst-dlmem-shm. It maps solib
into shm and checks that dlmem with that flag worked as expected,
by resolving the solib symbols. Then it checks the new functionality
of creating the library duplicate, that this flag permits.

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

Signed-off-by: Stas Sergeev <stsp2@yandex.ru>
---
 dlfcn/Makefile        |   5 +-
 dlfcn/dlfcn.h         |   3 +
 dlfcn/glreflib1.c     |   2 +
 dlfcn/tst-dlmem-shm.c | 169 ++++++++++++++++++++++++++++++++++++++++++
 elf/dl-load.c         |  25 ++++++-
 5 files changed, 202 insertions(+), 2 deletions(-)
 create mode 100644 dlfcn/tst-dlmem-shm.c

diff --git a/dlfcn/Makefile b/dlfcn/Makefile
index 8bca644168..755020af1e 100644
--- a/dlfcn/Makefile
+++ b/dlfcn/Makefile
@@ -52,8 +52,10 @@ endif
 ifeq (yes,$(build-shared))
 tests = glrefmain failtest tst-dladdr default errmsg1 tstcxaatexit \
 	bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2 \
-	bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen tst-dlmem-fdlopen
+	bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen tst-dlmem-fdlopen \
+	tst-dlmem-shm
 CPPFLAGS-tst-dlmem-fdlopen.c += -DBUILDDIR=\"$(objpfx)\"
+CPPFLAGS-tst-dlmem-shm.c += -DBUILDDIR=\"$(objpfx)\"
 endif
 modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \
 		defaultmod2 errmsg1mod modatexit modcxaatexit \
@@ -105,6 +107,7 @@ $(objpfx)failtest.out: $(objpfx)failtestmod.so
 
 $(objpfx)tst-dladdr.out: $(objpfx)glreflib1.so
 $(objpfx)tst-dlmem-fdlopen.out: $(objpfx)glreflib1.so
+$(objpfx)tst-dlmem-shm.out: $(objpfx)glreflib1.so
 
 $(objpfx)tst-dlinfo.out: $(objpfx)glreflib3.so
 LDFLAGS-glreflib3.so = -Wl,-rpath,:
diff --git a/dlfcn/dlfcn.h b/dlfcn/dlfcn.h
index 87dc4932fd..30bb532709 100644
--- a/dlfcn/dlfcn.h
+++ b/dlfcn/dlfcn.h
@@ -73,6 +73,9 @@ typedef void *
 (dlmem_premap_t) (void *mappref, size_t maplength, size_t mapalign,
 	          void *cookie);
 
+/* Do not replace destination mapping. dlmem() will then use memcpy(). */
+#define DLMEM_DONTREPLACE 1
+
 struct dlmem_args {
   /* Optional name to associate with the loaded object. */
   const char *soname;
diff --git a/dlfcn/glreflib1.c b/dlfcn/glreflib1.c
index f26832fabe..bab3fcd1b0 100644
--- a/dlfcn/glreflib1.c
+++ b/dlfcn/glreflib1.c
@@ -22,3 +22,5 @@ ref1 (void)
 {
   return 42;
 }
+
+int bar = 35;
diff --git a/dlfcn/tst-dlmem-shm.c b/dlfcn/tst-dlmem-shm.c
new file mode 100644
index 0000000000..7899dfc909
--- /dev/null
+++ b/dlfcn/tst-dlmem-shm.c
@@ -0,0 +1,169 @@
+/* Test for dlmem into shm.
+   Copyright (C) 2000-2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <dlfcn.h>
+#include <link.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <support/check.h>
+
+static size_t maplen;
+
+static void *
+premap_dlmem (void *mappref, size_t maplength, size_t mapalign, void *cookie)
+{
+  int fd = * (int *) cookie;
+  int prot = PROT_READ | PROT_WRITE;
+  int err;
+
+  /* See if we support such parameters. */
+  if (mappref || mapalign > 4096)
+    return MAP_FAILED;
+
+  fprintf (stderr, "%s\n", __func__);
+
+  err = ftruncate (fd, maplength);
+  if (err)
+    error (EXIT_FAILURE, 0, "ftruncate() failed");
+  maplen = maplength;
+  return mmap (NULL, maplength, prot, MAP_SHARED | MAP_FILE
+#ifdef MAP_32BIT
+                                      | MAP_32BIT
+#endif
+                                      , fd, 0);
+}
+
+#define TEST_FUNCTION do_test
+extern int do_test (void);
+
+int
+do_test (void)
+{
+  void *handle;
+  void *addr;
+  int (*sym) (void); /* We load ref1 from glreflib1.c.  */
+  int *bar, *bar2;
+  unsigned char *addr2;
+  Dl_info info;
+  int ret;
+  int fd;
+  int num;
+  off_t len;
+  struct link_map *lm;
+  const char *shm_name = "/tst-dlmem";
+  int shm_fd;
+  struct dlmem_args a;
+
+  shm_fd = memfd_create (shm_name, 0);
+  if (shm_fd == -1)
+    error (EXIT_FAILURE, 0, "shm_open() failed");
+
+  fd = open (BUILDDIR "glreflib1.so", O_RDONLY);
+  if (fd == -1)
+    error (EXIT_FAILURE, 0, "cannot open: glreflib1.so");
+  len = lseek (fd, 0, SEEK_END);
+  lseek (fd, 0, SEEK_SET);
+  addr = mmap (NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
+  if (addr == MAP_FAILED)
+    error (EXIT_FAILURE, 0, "cannot mmap: glreflib1.so");
+  a.soname = "glreflib1.so";
+  a.flags = DLMEM_DONTREPLACE;
+  a.nsid = LM_ID_BASE;
+  a.premap = premap_dlmem;
+  a.cookie = &shm_fd;
+  handle = dlmem (addr, len, RTLD_NOW | RTLD_LOCAL, &a);
+  if (handle == NULL)
+    error (EXIT_FAILURE, 0, "cannot load: glreflib1.so");
+  munmap (addr, len);
+  close (fd);
+  /* Check if premap was called. */
+  TEST_VERIFY (maplen != 0);
+
+  sym = dlsym (handle, "ref1");
+  if (sym == NULL)
+    error (EXIT_FAILURE, 0, "dlsym failed");
+
+  memset (&info, 0, sizeof (info));
+  ret = dladdr (sym, &info);
+  if (ret == 0)
+    error (EXIT_FAILURE, 0, "dladdr failed");
+#ifdef MAP_32BIT
+  /* Make sure MAP_32BIT worked. */
+  if ((unsigned long) info.dli_fbase >= 0x100000000)
+    error (EXIT_FAILURE, 0, "premap audit didn't work");
+#endif
+  ret = dlinfo (handle, RTLD_DI_LINKMAP, &lm);
+  if (ret != 0)
+    error (EXIT_FAILURE, 0, "dlinfo failed");
+
+  printf ("info.dli_fname = %p (\"%s\")\n", info.dli_fname, info.dli_fname);
+  printf ("info.dli_fbase = %p\n", info.dli_fbase);
+  printf ("info.dli_sname = %p (\"%s\")\n", info.dli_sname, info.dli_sname);
+  printf ("info.dli_saddr = %p\n", info.dli_saddr);
+  printf ("lm->l_addr = %lx\n", lm->l_addr);
+
+  if (info.dli_fname == NULL)
+    error (EXIT_FAILURE, 0, "dli_fname is NULL");
+  if (info.dli_fbase == NULL)
+    error (EXIT_FAILURE, 0, "dli_fbase is NULL");
+  if (info.dli_sname == NULL)
+    error (EXIT_FAILURE, 0, "dli_sname is NULL");
+  if (info.dli_saddr == NULL)
+    error (EXIT_FAILURE, 0, "dli_saddr is NULL");
+
+  num = sym ();
+  if (num != 42)
+    error (EXIT_FAILURE, 0, "bad return from ref1");
+
+  /* Now try symbol duplication. */
+  bar = dlsym (handle, "bar");
+  if (bar == NULL)
+    error (EXIT_FAILURE, 0, "dlsym failed");
+  TEST_COMPARE (*bar, 35);
+  /* write another value */
+#define TEST_BAR_VAL 48
+  *bar = TEST_BAR_VAL;
+
+  /* Create second instance of the solib. */
+  addr2 = mmap (NULL, maplen, PROT_READ | PROT_WRITE | PROT_EXEC,
+               MAP_SHARED, shm_fd, 0);
+  if (addr2 == MAP_FAILED)
+    error (EXIT_FAILURE, 0, "cannot mmap shm\n");
+  /* Find our bar symbol duplicate. */
+  ret = dladdr (bar, &info);
+  if (ret == 0)
+    error (EXIT_FAILURE, 0, "dladdr failed");
+  bar2 = (int *) (addr2 + (info.dli_saddr - info.dli_fbase));
+  /* See if we found the right one. */
+  TEST_COMPARE (*bar2, TEST_BAR_VAL);
+
+  munmap (addr2, maplen);
+  close (shm_fd);
+  dlclose (handle);
+
+  return 0;
+}
+
+
+#include <support/test-driver.c>
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 2550173f48..e7216c74c3 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -2385,6 +2385,25 @@ do_memremap (void *addr, size_t length, int prot, int flags,
   return addr;
 }
 
+static void *
+do_mmapcpy (void *addr, size_t length, int prot, int flags,
+            void *arg, off_t offset)
+{
+  const struct dlmem_fbuf *fb = arg;
+
+  assert (flags & MAP_FIXED);
+  if (offset < fb->len)
+    {
+      size_t to_copy = length;
+      if (offset + to_copy > fb->len)
+        to_copy = fb->len - offset;
+      memcpy (addr, fb->buf + offset, to_copy);
+    }
+  if (__mprotect (addr, length, prot) == -1)
+    return MAP_FAILED;
+  return addr;
+}
+
 static void *
 do_dlmem_premap (void *mappref, size_t maplength, size_t mapalign,
 		 void *cookie)
@@ -2428,6 +2447,10 @@ ___dl_map_object_from_mem (struct link_map *loader, const char *name,
   struct r_debug *r = _dl_debug_update (nsid);
   bool make_consistent = false;
   struct r_file_id id = {};
+  const struct dlmem_fbuf *fb = private;
+  unsigned dlmem_flags = fb->dlm_args ? fb->dlm_args->flags : 0;
+  __typeof (do_mmap) *m_map = (dlmem_flags & DLMEM_DONTREPLACE)
+                             ? do_mmapcpy : do_memremap;
 
   assert (nsid >= 0);
   assert (nsid < GL(dl_nns));
@@ -2478,7 +2501,7 @@ ___dl_map_object_from_mem (struct link_map *loader, const char *name,
 
   void *stack_end = __libc_stack_end;
   if (_ld_map_object_1 (l, private, fbp, mode, loader, &stack_end, &errval,
-                        &errstring, do_memremap, do_dlmem_premap))
+                        &errstring, m_map, do_dlmem_premap))
     goto lose;
 
   _ld_map_object_2 (l, mode, id, NULL, nsid, r, &make_consistent);
-- 
2.37.2


  parent reply	other threads:[~2023-03-18 16:52 UTC|newest]

Thread overview: 107+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-18 16:50 [PATCH v9 0/13] implement dlmem() function Stas Sergeev
2023-03-18 16:50 ` [PATCH 01/13] elf: strdup() l_name if no realname [BZ #30100] Stas Sergeev
2023-03-29 13:54   ` Adhemerval Zanella Netto
2023-03-29 14:12     ` stsp
2023-03-29 14:19       ` Adhemerval Zanella Netto
2023-03-29 14:28         ` stsp
2023-03-29 14:30           ` Adhemerval Zanella Netto
2023-03-29 14:33             ` stsp
2023-03-18 16:50 ` [PATCH 02/13] elf: switch _dl_map_segment() to anonymous mapping Stas Sergeev
2023-03-29 17:01   ` Adhemerval Zanella Netto
2023-03-29 18:00     ` stsp
2023-03-29 18:29       ` Adhemerval Zanella Netto
2023-03-29 18:46         ` stsp
2023-03-29 19:17           ` Adhemerval Zanella Netto
2023-03-29 19:43             ` stsp
2023-03-18 16:51 ` [PATCH 03/13] elf: dont pass fd to _dl_process_pt_xx Stas Sergeev
2023-03-29 17:10   ` Adhemerval Zanella Netto
2023-03-30 16:08     ` stsp
2023-03-30 20:46       ` Adhemerval Zanella Netto
2023-03-31 12:02         ` Szabolcs Nagy
2023-03-31 12:54           ` Adhemerval Zanella Netto
2023-03-31 14:04             ` stsp
2023-03-18 16:51 ` [PATCH 04/13] elf: split _dl_map_object_from_fd() into reusable parts Stas Sergeev
2023-03-18 16:51 ` [PATCH 05/13] elf: split open_verify() " Stas Sergeev
2023-03-18 16:51 ` [PATCH 06/13] elf: load elf hdr fully in open_verify() Stas Sergeev
2023-03-18 16:51 ` [PATCH 07/13] elf: convert pread64 to callback in do_open_verify() Stas Sergeev
2023-03-18 16:51 ` [PATCH 08/13] elf: convert _dl_map_segments's mmap() to a callback Stas Sergeev
2023-03-18 16:51 ` [PATCH 09/13] elf: call _dl_map_segment() via premap callback Stas Sergeev
2023-03-18 16:51 ` [PATCH 10/13] elf: convert _dl_map_object to a callback Stas Sergeev
2023-03-18 16:51 ` [PATCH 11/13] elf: split _dl_check_loaded() from _dl_map_object Stas Sergeev
2023-03-18 16:51 ` [PATCH 12/13] dlfcn,elf: implement dlmem() [BZ #11767] Stas Sergeev
2023-03-29 13:45   ` Carlos O'Donell
2023-03-29 13:51     ` stsp
2023-03-29 14:10       ` Jonathon Anderson
2023-03-29 14:20         ` stsp
2023-03-29 14:31           ` Adhemerval Zanella Netto
2023-03-29 15:01             ` stsp
2023-03-29 14:35           ` Carlos O'Donell
2023-03-29 14:50             ` stsp
2023-03-29 15:20               ` Carlos O'Donell
2023-03-29 15:34                 ` stsp
2023-03-30  8:09         ` stsp
2023-03-18 16:51 ` Stas Sergeev [this message]
2023-03-29 12:32 ` [PATCH v9 0/13] implement dlmem() function Adhemerval Zanella Netto
2023-03-29 13:10   ` stsp
2023-03-29 13:18   ` stsp
2023-03-31 12:20     ` Szabolcs Nagy
2023-03-31 13:51       ` stsp
2023-03-31 14:49         ` Rich Felker
2023-03-31 14:56           ` stsp
2023-03-31 14:58             ` Rich Felker
2023-03-31 15:03               ` stsp
2023-03-31 14:44       ` stsp
2023-03-31 15:12       ` stsp
2023-03-31 17:12         ` Szabolcs Nagy
2023-03-31 17:36           ` stsp
2023-04-01  9:28             ` stsp
2023-04-03 10:04             ` Szabolcs Nagy
2023-04-03 10:43               ` stsp
2023-04-03 12:01                 ` Szabolcs Nagy
2023-04-03 13:07                   ` stsp
2023-04-05  7:29                   ` stsp
2023-04-05  8:51                     ` Szabolcs Nagy
2023-04-05  9:26                       ` stsp
2023-04-05  9:31                       ` Florian Weimer
2023-04-12 17:23                       ` stsp
2023-04-12 18:00                         ` stsp
2023-04-12 18:20                           ` Rich Felker
2023-04-12 18:46                             ` stsp
2023-04-12 19:52                               ` Zack Weinberg
2023-04-12 19:07                             ` stsp
2023-04-13 10:01                             ` stsp
2023-04-13 12:38                               ` Szabolcs Nagy
2023-04-13 15:59                                 ` stsp
2023-04-13 18:09                                   ` Adhemerval Zanella Netto
2023-04-13 18:59                                     ` stsp
2023-04-13 19:12                                       ` Adhemerval Zanella Netto
2023-04-13 19:29                                         ` stsp
2023-04-13 20:02                                           ` Adhemerval Zanella Netto
2023-04-13 20:21                                             ` stsp
2023-04-13 20:57                                             ` stsp
2023-04-14  7:07                                             ` stsp
2023-04-14  7:36                                             ` stsp
2023-04-14 11:30                                             ` stsp
2023-04-14 19:04                                             ` proof for dlmem() (Re: [PATCH v9 0/13] implement dlmem() function) stsp
2023-05-01 23:11                                               ` Zack Weinberg
2023-05-02  5:48                                                 ` stsp
2023-05-08 16:00                                                   ` stsp
2023-05-02  6:24                                                 ` stsp
2023-05-08 15:10                                 ` [PATCH v9 0/13] implement dlmem() function stsp
2023-03-31 18:47           ` stsp
2023-03-31 19:00             ` stsp
2023-03-29 13:17 ` Carlos O'Donell
2023-03-29 13:26   ` stsp
2023-03-29 17:03   ` stsp
2023-03-29 18:13     ` Carlos O'Donell
2023-03-29 18:29       ` stsp
2023-03-31 11:04       ` stsp
2023-04-13 21:17         ` Carlos O'Donell
2023-04-13 21:58           ` stsp
2023-04-13 22:08           ` stsp
2023-04-13 22:50           ` stsp
2023-04-14 16:15           ` Autoconf maintenance (extremely tangential to Re: [PATCH v9 0/13] implement dlmem() function) Zack Weinberg
2023-04-14 20:24             ` Carlos O'Donell
2023-04-14 20:40               ` Zack Weinberg
2023-05-08 15:05           ` [PATCH v9 0/13] implement dlmem() function stsp
2023-05-19  7:26           ` stsp

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230318165110.3672749-14-stsp2@yandex.ru \
    --to=stsp2@yandex.ru \
    --cc=libc-alpha@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).