@@ -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. */
@@ -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,
@@ -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;
@@ -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;
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(-)