From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from forward204c.mail.yandex.net (forward204c.mail.yandex.net [IPv6:2a02:6b8:c03:500:1:45:d181:d204]) by sourceware.org (Postfix) with ESMTPS id 9504D384D19F for ; Mon, 3 Apr 2023 09:05:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9504D384D19F Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=yandex.ru Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=yandex.ru Received: from mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net (mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net [IPv6:2a02:6b8:c0c:a810:0:640:6b9b:0]) by forward204c.mail.yandex.net (Yandex) with ESMTP id 9E6B7600FE for ; Mon, 3 Apr 2023 12:04:59 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id h4J5UKjDcmI0-cHVfVnxi; Mon, 03 Apr 2023 12:04:58 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex.ru; s=mail; t=1680512699; bh=SNqX3FePTFTANMNXr3iLqM82U8QjLTNGydq0W4AgTw0=; h=Message-Id:Date:In-Reply-To:Cc:Subject:References:To:From; b=uYCTPQfWZfE3ydtKXVt8yaGSLFvESuunkXCXz4RUM/qsl11KYaJkK+sI1ufhiZDaT xslp4fQDgZemMPzH2d3mVBYvd/w8YacF0VT3hbS+EWNJ8TJILdyZagWdKMEj2x1x3V cuaepVv4vQqkJj2J7FTDKerCLumLIKOGeUxZFXcI= Authentication-Results: mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net; dkim=pass header.i=@yandex.ru From: Stas Sergeev To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 12/12] dlfcn,elf: impl DLMEM_GENBUF_SRC dlmem() flag Date: Mon, 3 Apr 2023 14:04:21 +0500 Message-Id: <20230403090421.560208-13-stsp2@yandex.ru> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20230403090421.560208-1-stsp2@yandex.ru> References: <20230403090421.560208-1-stsp2@yandex.ru> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.2 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,GIT_PATCH_0,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: 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 --- 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