From patchwork Mon Apr 3 09:04:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 1764354 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.a=rsa-sha256 header.s=default header.b=DUzE6/ei; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PqlRJ47cKz1yYb for ; Mon, 3 Apr 2023 19:07:56 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 800C13887F66 for ; Mon, 3 Apr 2023 09:07:54 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 800C13887F66 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680512874; bh=SNqX3FePTFTANMNXr3iLqM82U8QjLTNGydq0W4AgTw0=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=DUzE6/eiuL0rN+Ss3U7KIMc3wVzU3vENBst5cYKn1G6RTsztn12a563WMFfxatqOn aJ6JXzfGwYH9CTnNTbXgskOHr3dQ2I8wceLVM9mCN3ny1XaQ+ZgVLyezVtIfYHU6oj zNreJmGL9OPJZHq2twTcipQDT3OM3BuB2XWR8WKw= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org 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 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 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 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 X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Stas Sergeev via Libc-alpha From: stsp Reply-To: Stas Sergeev Errors-To: libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org Sender: "Libc-alpha" 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;