From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from forward102p.mail.yandex.net (forward102p.mail.yandex.net [77.88.28.102]) by sourceware.org (Postfix) with ESMTPS id 1AC52385020B for ; Sat, 18 Mar 2023 16:52:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1AC52385020B 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 myt6-1289f562e823.qloud-c.yandex.net (myt6-1289f562e823.qloud-c.yandex.net [IPv6:2a02:6b8:c12:259d:0:640:1289:f562]) by forward102p.mail.yandex.net (Yandex) with ESMTP id 77563393D66E for ; Sat, 18 Mar 2023 19:52:00 +0300 (MSK) Received: by myt6-1289f562e823.qloud-c.yandex.net (smtp/Yandex) with ESMTPSA id cpp3fcrbC8c1-7FRHiJc7; Sat, 18 Mar 2023 19:51:59 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex.ru; s=mail; t=1679158320; bh=aGUxLu47DxBQq/PH085NFGfWvDHjJa4Ru2Zvy+ExPM4=; h=Message-Id:Date:In-Reply-To:Cc:Subject:References:To:From; b=cdwZHJRPVw7wb09Sop+ziIo5geOClenVVLMqTmskQ3ML0/mp1YCYxmdYKXDXk2Ybj 9bt6/r2x10mdA21BXvzgPBuFMXr///F97cn+Hq/zNWPiywNxA77APFH+SiRrez637B kakBQsBb+DsKXMdo5eUnhC38FraYV9A81lV72u0I= Authentication-Results: myt6-1289f562e823.qloud-c.yandex.net; dkim=pass header.i=@yandex.ru From: Stas Sergeev To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 13/13] dlfcn,elf: impl DLMEM_DONTREPLACE dlmem() flag Date: Sat, 18 Mar 2023 21:51:10 +0500 Message-Id: <20230318165110.3672749-14-stsp2@yandex.ru> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20230318165110.3672749-1-stsp2@yandex.ru> References: <20230318165110.3672749-1-stsp2@yandex.ru> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.8 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,KAM_SHORT,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,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 preserves the destination mapping by using memcpy() from the source buffer. It is useful if the backing-store was mapped with MAP_SHARED. This patch adds a test-case named tst-dlmem-shm. It maps solib into shm and checks that dlmem with that flag worked as expected, by resolving the solib symbols. Then it checks the new functionality of creating the library duplicate, that this flag permits. The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev --- dlfcn/Makefile | 5 +- dlfcn/dlfcn.h | 3 + dlfcn/glreflib1.c | 2 + dlfcn/tst-dlmem-shm.c | 169 ++++++++++++++++++++++++++++++++++++++++++ elf/dl-load.c | 25 ++++++- 5 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 dlfcn/tst-dlmem-shm.c diff --git a/dlfcn/Makefile b/dlfcn/Makefile index 8bca644168..755020af1e 100644 --- a/dlfcn/Makefile +++ b/dlfcn/Makefile @@ -52,8 +52,10 @@ endif ifeq (yes,$(build-shared)) tests = glrefmain failtest tst-dladdr default errmsg1 tstcxaatexit \ bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2 \ - bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen tst-dlmem-fdlopen + bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen tst-dlmem-fdlopen \ + tst-dlmem-shm CPPFLAGS-tst-dlmem-fdlopen.c += -DBUILDDIR=\"$(objpfx)\" +CPPFLAGS-tst-dlmem-shm.c += -DBUILDDIR=\"$(objpfx)\" endif modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \ defaultmod2 errmsg1mod modatexit modcxaatexit \ @@ -105,6 +107,7 @@ $(objpfx)failtest.out: $(objpfx)failtestmod.so $(objpfx)tst-dladdr.out: $(objpfx)glreflib1.so $(objpfx)tst-dlmem-fdlopen.out: $(objpfx)glreflib1.so +$(objpfx)tst-dlmem-shm.out: $(objpfx)glreflib1.so $(objpfx)tst-dlinfo.out: $(objpfx)glreflib3.so LDFLAGS-glreflib3.so = -Wl,-rpath,: diff --git a/dlfcn/dlfcn.h b/dlfcn/dlfcn.h index 87dc4932fd..30bb532709 100644 --- a/dlfcn/dlfcn.h +++ b/dlfcn/dlfcn.h @@ -73,6 +73,9 @@ typedef void * (dlmem_premap_t) (void *mappref, size_t maplength, size_t mapalign, void *cookie); +/* Do not replace destination mapping. dlmem() will then use memcpy(). */ +#define DLMEM_DONTREPLACE 1 + struct dlmem_args { /* Optional name to associate with the loaded object. */ const char *soname; diff --git a/dlfcn/glreflib1.c b/dlfcn/glreflib1.c index f26832fabe..bab3fcd1b0 100644 --- a/dlfcn/glreflib1.c +++ b/dlfcn/glreflib1.c @@ -22,3 +22,5 @@ ref1 (void) { return 42; } + +int bar = 35; diff --git a/dlfcn/tst-dlmem-shm.c b/dlfcn/tst-dlmem-shm.c new file mode 100644 index 0000000000..7899dfc909 --- /dev/null +++ b/dlfcn/tst-dlmem-shm.c @@ -0,0 +1,169 @@ +/* Test for dlmem into shm. + Copyright (C) 2000-2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static size_t maplen; + +static void * +premap_dlmem (void *mappref, size_t maplength, size_t mapalign, void *cookie) +{ + int fd = * (int *) cookie; + int prot = PROT_READ | PROT_WRITE; + int err; + + /* See if we support such parameters. */ + if (mappref || mapalign > 4096) + return MAP_FAILED; + + fprintf (stderr, "%s\n", __func__); + + err = ftruncate (fd, maplength); + if (err) + error (EXIT_FAILURE, 0, "ftruncate() failed"); + maplen = maplength; + return mmap (NULL, maplength, prot, MAP_SHARED | MAP_FILE +#ifdef MAP_32BIT + | MAP_32BIT +#endif + , fd, 0); +} + +#define TEST_FUNCTION do_test +extern int do_test (void); + +int +do_test (void) +{ + void *handle; + void *addr; + int (*sym) (void); /* We load ref1 from glreflib1.c. */ + int *bar, *bar2; + unsigned char *addr2; + Dl_info info; + int ret; + int fd; + int num; + off_t len; + struct link_map *lm; + const char *shm_name = "/tst-dlmem"; + int shm_fd; + struct dlmem_args a; + + shm_fd = memfd_create (shm_name, 0); + if (shm_fd == -1) + error (EXIT_FAILURE, 0, "shm_open() failed"); + + fd = open (BUILDDIR "glreflib1.so", O_RDONLY); + if (fd == -1) + error (EXIT_FAILURE, 0, "cannot open: glreflib1.so"); + len = lseek (fd, 0, SEEK_END); + lseek (fd, 0, SEEK_SET); + 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; + a.premap = premap_dlmem; + a.cookie = &shm_fd; + handle = dlmem (addr, len, RTLD_NOW | RTLD_LOCAL, &a); + if (handle == NULL) + error (EXIT_FAILURE, 0, "cannot load: glreflib1.so"); + munmap (addr, len); + close (fd); + /* Check if premap was called. */ + TEST_VERIFY (maplen != 0); + + sym = dlsym (handle, "ref1"); + if (sym == NULL) + error (EXIT_FAILURE, 0, "dlsym failed"); + + memset (&info, 0, sizeof (info)); + ret = dladdr (sym, &info); + if (ret == 0) + error (EXIT_FAILURE, 0, "dladdr failed"); +#ifdef MAP_32BIT + /* Make sure MAP_32BIT worked. */ + if ((unsigned long) info.dli_fbase >= 0x100000000) + error (EXIT_FAILURE, 0, "premap audit didn't work"); +#endif + ret = dlinfo (handle, RTLD_DI_LINKMAP, &lm); + if (ret != 0) + error (EXIT_FAILURE, 0, "dlinfo failed"); + + printf ("info.dli_fname = %p (\"%s\")\n", info.dli_fname, info.dli_fname); + printf ("info.dli_fbase = %p\n", info.dli_fbase); + printf ("info.dli_sname = %p (\"%s\")\n", info.dli_sname, info.dli_sname); + printf ("info.dli_saddr = %p\n", info.dli_saddr); + printf ("lm->l_addr = %lx\n", lm->l_addr); + + if (info.dli_fname == NULL) + error (EXIT_FAILURE, 0, "dli_fname is NULL"); + if (info.dli_fbase == NULL) + error (EXIT_FAILURE, 0, "dli_fbase is NULL"); + if (info.dli_sname == NULL) + error (EXIT_FAILURE, 0, "dli_sname is NULL"); + if (info.dli_saddr == NULL) + error (EXIT_FAILURE, 0, "dli_saddr is NULL"); + + num = sym (); + if (num != 42) + error (EXIT_FAILURE, 0, "bad return from ref1"); + + /* Now try symbol duplication. */ + bar = dlsym (handle, "bar"); + if (bar == NULL) + error (EXIT_FAILURE, 0, "dlsym failed"); + TEST_COMPARE (*bar, 35); + /* write another value */ +#define TEST_BAR_VAL 48 + *bar = TEST_BAR_VAL; + + /* Create second instance of the solib. */ + addr2 = mmap (NULL, maplen, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_SHARED, shm_fd, 0); + if (addr2 == MAP_FAILED) + error (EXIT_FAILURE, 0, "cannot mmap shm\n"); + /* Find our bar symbol duplicate. */ + ret = dladdr (bar, &info); + if (ret == 0) + error (EXIT_FAILURE, 0, "dladdr failed"); + bar2 = (int *) (addr2 + (info.dli_saddr - info.dli_fbase)); + /* See if we found the right one. */ + TEST_COMPARE (*bar2, TEST_BAR_VAL); + + munmap (addr2, maplen); + close (shm_fd); + dlclose (handle); + + return 0; +} + + +#include diff --git a/elf/dl-load.c b/elf/dl-load.c index 2550173f48..e7216c74c3 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -2385,6 +2385,25 @@ do_memremap (void *addr, size_t length, int prot, int flags, return addr; } +static void * +do_mmapcpy (void *addr, size_t length, int prot, int flags, + void *arg, off_t offset) +{ + const struct dlmem_fbuf *fb = arg; + + assert (flags & MAP_FIXED); + if (offset < fb->len) + { + size_t to_copy = length; + if (offset + to_copy > fb->len) + to_copy = fb->len - offset; + memcpy (addr, fb->buf + offset, to_copy); + } + if (__mprotect (addr, length, prot) == -1) + return MAP_FAILED; + return addr; +} + static void * do_dlmem_premap (void *mappref, size_t maplength, size_t mapalign, void *cookie) @@ -2428,6 +2447,10 @@ ___dl_map_object_from_mem (struct link_map *loader, const char *name, struct r_debug *r = _dl_debug_update (nsid); bool make_consistent = false; struct r_file_id id = {}; + const struct dlmem_fbuf *fb = private; + unsigned dlmem_flags = fb->dlm_args ? fb->dlm_args->flags : 0; + __typeof (do_mmap) *m_map = (dlmem_flags & DLMEM_DONTREPLACE) + ? do_mmapcpy : do_memremap; assert (nsid >= 0); assert (nsid < GL(dl_nns)); @@ -2478,7 +2501,7 @@ ___dl_map_object_from_mem (struct link_map *loader, const char *name, void *stack_end = __libc_stack_end; if (_ld_map_object_1 (l, private, fbp, mode, loader, &stack_end, &errval, - &errstring, do_memremap, do_dlmem_premap)) + &errstring, m_map, do_dlmem_premap)) goto lose; _ld_map_object_2 (l, mode, id, NULL, nsid, r, &make_consistent); -- 2.37.2