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 12/12] dlfcn,elf: impl DLMEM_GENBUF_SRC dlmem() flag
Date: Mon,  3 Apr 2023 14:04:21 +0500	[thread overview]
Message-ID: <20230403090421.560208-13-stsp2@yandex.ru> (raw)
In-Reply-To: <20230403090421.560208-1-stsp2@yandex.ru>

This flag allows to use a generic unaligned memory buffer or a
private anonymous mapping as a source. It should not be preferred
over a file-backed mapping when possible, but the "bad" cases also
needs to be supported.

New tests added to tst-dlmem-shm test-case.

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

Signed-off-by: Stas Sergeev <stsp2@yandex.ru>
---
 dlfcn/dlfcn.h         |  4 ++++
 dlfcn/dlmem.c         |  6 +++++-
 dlfcn/tst-dlmem-shm.c | 37 ++++++++++++++++++++++++++++++++++++-
 elf/dl-load.c         |  6 ++++++
 4 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/dlfcn/dlfcn.h b/dlfcn/dlfcn.h
index 7aa9d7d3cf..976d93a464 100644
--- a/dlfcn/dlfcn.h
+++ b/dlfcn/dlfcn.h
@@ -76,6 +76,10 @@ typedef void *
 /* Do not replace mapping created by premap callback.
    dlmem() will then use memcpy(). */
 #define DLMEM_DONTREPLACE 1
+/* Treat source memory buffer as a generic unaligned buffer, rather
+   than a file-backed or anonymously-shared mapping. Anonymous private
+   mapping also needs this flag to be set. */
+#define DLMEM_GENBUF_SRC 2
 
 struct dlmem_args {
   /* Optional name to associate with the loaded object. */
diff --git a/dlfcn/dlmem.c b/dlfcn/dlmem.c
index d59eb99ec1..fc8facb6d2 100644
--- a/dlfcn/dlmem.c
+++ b/dlfcn/dlmem.c
@@ -40,12 +40,16 @@ static void
 dlmem_doit (void *a)
 {
   struct _dlmem_args *args = (struct _dlmem_args *) a;
+  const struct dlmem_args *dlm_args = args->args;
 
   if (args->mode & ~(RTLD_BINDING_MASK | RTLD_NOLOAD | RTLD_DEEPBIND
 		     | RTLD_GLOBAL | RTLD_LOCAL | RTLD_NODELETE
 		     | __RTLD_SPROF))
     _dl_signal_error (EINVAL, NULL, NULL, _("invalid mode parameter"));
-  if ((uintptr_t) args->buffer & (GLRO(dl_pagesize) - 1))
+
+  /* Unaligned buffer is only permitted when DLMEM_GENBUF_SRC flag set. */
+  if (((uintptr_t) args->buffer & (GLRO(dl_pagesize) - 1))
+      && (!dlm_args || !(dlm_args->flags & DLMEM_GENBUF_SRC)))
     _dl_signal_error (EINVAL, NULL, NULL, _("buffer not aligned"));
 
   args->new = GLRO(dl_mem) (args->buffer, args->size,
diff --git a/dlfcn/tst-dlmem-shm.c b/dlfcn/tst-dlmem-shm.c
index 7899dfc909..16d13f16d6 100644
--- a/dlfcn/tst-dlmem-shm.c
+++ b/dlfcn/tst-dlmem-shm.c
@@ -70,10 +70,11 @@ do_test (void)
   int fd;
   int num;
   off_t len;
+  off_t orig_len;
   struct link_map *lm;
   const char *shm_name = "/tst-dlmem";
   int shm_fd;
-  struct dlmem_args a;
+  struct dlmem_args a = {};
 
   shm_fd = memfd_create (shm_name, 0);
   if (shm_fd == -1)
@@ -84,9 +85,43 @@ do_test (void)
     error (EXIT_FAILURE, 0, "cannot open: glreflib1.so");
   len = lseek (fd, 0, SEEK_END);
   lseek (fd, 0, SEEK_SET);
+  /* For the sake of testing add extra space. */
+  orig_len = len;
+  len += 4096;
   addr = mmap (NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
   if (addr == MAP_FAILED)
     error (EXIT_FAILURE, 0, "cannot mmap: glreflib1.so");
+
+  /* Try unaligned buffer. */
+  handle = dlmem (addr + 4, len, RTLD_NOW | RTLD_LOCAL, NULL);
+  TEST_VERIFY (handle == NULL);
+  /* errno is set by dlerror() so needs to print something. */
+  printf ("unaligned buf gives %s\n", dlerror ());
+  TEST_COMPARE (errno, EINVAL);
+  /* Try allow unaligned buffer but not at the beginning of solib. */
+  a.flags = DLMEM_GENBUF_SRC;
+  handle = dlmem (addr + 4, len, RTLD_NOW | RTLD_LOCAL, &a);
+  TEST_VERIFY (handle == NULL);
+  printf ("non-elf data gives %s\n", dlerror ());
+  TEST_COMPARE (errno, EINVAL);
+  /* Try allow unaligned buffer but with good solib. */
+  mprotect (addr, len, PROT_READ | PROT_WRITE);
+  memmove (addr + 4, addr, orig_len);
+  /* Forgot to allow unaligned buffer. */
+  handle = dlmem (addr + 4, len, RTLD_NOW | RTLD_LOCAL, NULL);
+  TEST_VERIFY (handle == NULL);
+  /* Should now be well. */
+  handle = dlmem (addr + 4, len, RTLD_NOW | RTLD_LOCAL, &a);
+  TEST_VERIFY (handle != NULL);
+
+  /* Lets do this all again, now for real. */
+  dlclose (handle);
+  munmap (addr, len);
+  len = orig_len;
+  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;
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 422c03459b..002afbee3f 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -2382,6 +2382,7 @@ do_memremap (void *addr, size_t length, int prot, int flags,
              void *arg, off_t offset)
 {
   const struct dlmem_fbuf *fb = arg;
+  const struct dlmem_args *dlm_args = fb->dlm_args;
   size_t to_copy = 0;
 
   assert (flags & MAP_FIXED);
@@ -2390,6 +2391,11 @@ do_memremap (void *addr, size_t length, int prot, int flags,
   if (flags & MAP_ANONYMOUS)
     return __mmap (addr, length, prot, flags, -1, 0);
 
+  /* With DLMEM_GENBUF_SRC flag, everything but anonymous mmaps goes
+     to memcpy. */
+  if (dlm_args && (dlm_args->flags & DLMEM_GENBUF_SRC))
+    return do_mmapcpy(addr, length, prot, flags, arg, offset);
+
   if (offset < fb->len)
     {
       to_copy = length;
-- 
2.37.2


      parent reply	other threads:[~2023-04-03  9:05 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-03  9:04 [PATCH v10 0/12] implement dlmem() function Stas Sergeev
2023-04-03  9:04 ` [PATCH 01/12] elf: split _dl_map_object_from_fd() into reusable parts Stas Sergeev
2023-04-03  9:04 ` [PATCH 02/12] elf: split open_verify() " Stas Sergeev
2023-04-03  9:04 ` [PATCH 03/12] elf: split _dl_check_loaded() from _dl_map_object Stas Sergeev
2023-04-03  9:04 ` [PATCH 04/12] elf: load elf hdr fully in open_verify() Stas Sergeev
2023-04-03  9:04 ` [PATCH 05/12] elf: switch _dl_map_segment() to anonymous mapping Stas Sergeev
2023-04-03  9:04 ` [PATCH 06/12] elf: convert pread64 to callback in do_open_verify() Stas Sergeev
2023-04-03  9:04 ` [PATCH 07/12] elf: convert _dl_map_segments's mmap() to a callback Stas Sergeev
2023-04-03  9:04 ` [PATCH 08/12] elf: call _dl_map_segment() via premap callback Stas Sergeev
2023-04-03  9:04 ` [PATCH 09/12] elf: convert _dl_map_object to a callback Stas Sergeev
2023-04-03  9:04 ` [PATCH 10/12] dlfcn,elf: implement dlmem() [BZ #11767] Stas Sergeev
2023-04-03  9:04 ` [PATCH 11/12] dlfcn,elf: impl DLMEM_DONTREPLACE dlmem() flag Stas Sergeev
2023-04-03  9:04 ` Stas Sergeev [this message]

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=20230403090421.560208-13-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).