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
prev 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).