From patchwork Mon Apr 3 09:04:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 67197 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5A7C63850437 for ; Mon, 3 Apr 2023 09:06:01 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5A7C63850437 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680512761; bh=Gbhr4/BAMK7RGCoMxuNF9NkE9VIWN/m5gPh2+tT0Bmw=; 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=PctCRkHDjV8HblTkSIm6uDfna12OyfYZ5BumJjNu++cs1+9QjI57XM/7TCZE9axNO Sur73jsFnFM6M+PsNJJXrAHr7l/PPMq2zCL0hLzuP98yfj4szzsM7jtXC1tJ0NjIQw AVnObovxTGtubE5io2USbmrKhavudOilYwMmmboU= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from forward202c.mail.yandex.net (forward202c.mail.yandex.net [IPv6:2a02:6b8:c03:500:1:45:d181:d202]) by sourceware.org (Postfix) with ESMTPS id 5D16838768B1 for ; Mon, 3 Apr 2023 09:04:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5D16838768B1 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 forward202c.mail.yandex.net (Yandex) with ESMTP id C5D20600D1 for ; Mon, 3 Apr 2023 12:04:46 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id h4J5UKjDcmI0-1nQged5G; Mon, 03 Apr 2023 12:04:46 +0300 X-Yandex-Fwd: 1 To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 01/12] elf: split _dl_map_object_from_fd() into reusable parts Date: Mon, 3 Apr 2023 14:04:10 +0500 Message-Id: <20230403090421.560208-2-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.0 required=5.0 tests=BAYES_00, DKIM_INVALID, DKIM_SIGNED, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, GIT_PATCH_0, KAM_DMARC_STATUS, 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+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" This is mostly a mechanical split, with just a very minor moves of 2 small code fragments. This change should introduce no functional differences. The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev --- elf/dl-load.c | 329 ++++++++++++++++++++++++++++---------------------- 1 file changed, 185 insertions(+), 144 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index 9a0e40c0e9..6b2c3ac6bf 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -929,137 +929,46 @@ _dl_process_pt_gnu_property (struct link_map *l, int fd, const ElfW(Phdr) *ph) } } +static void +_dl_process_phdrs (struct link_map *l, int fd) +{ + const ElfW(Phdr) *ph; -/* Map in the shared object NAME, actually located in REALNAME, and already - opened on FD. */ + /* Process program headers again after load segments are mapped in + case processing requires accessing those segments. Scan program + headers backward so that PT_NOTE can be skipped if PT_GNU_PROPERTY + exits. */ + for (ph = &l->l_phdr[l->l_phnum]; ph != l->l_phdr; --ph) + switch (ph[-1].p_type) + { + case PT_NOTE: + _dl_process_pt_note (l, fd, &ph[-1]); + break; + case PT_GNU_PROPERTY: + _dl_process_pt_gnu_property (l, fd, &ph[-1]); + break; + } +} -#ifndef EXTERNAL_MAP_FROM_FD -static -#endif -struct link_map * -_dl_map_object_from_fd (const char *name, const char *origname, int fd, - struct filebuf *fbp, char *realname, - struct link_map *loader, int l_type, int mode, - void **stack_endp, Lmid_t nsid) +static int +_dl_map_object_1 (struct link_map *l, int fd, + struct filebuf *fbp, + int mode, struct link_map *loader, + void **stack_endp, int *errval_p, + const char **errstring_p) { - struct link_map *l = NULL; const ElfW(Ehdr) *header; const ElfW(Phdr) *phdr; const ElfW(Phdr) *ph; size_t maplength; int type; /* Initialize to keep the compiler happy. */ - const char *errstring = NULL; - int errval = 0; - - /* Get file information. To match the kernel behavior, do not fill - in this information for the executable in case of an explicit - loader invocation. */ - struct r_file_id id; - if (mode & __RTLD_OPENEXEC) - { - assert (nsid == LM_ID_BASE); - memset (&id, 0, sizeof (id)); - } - else - { - if (__glibc_unlikely (!_dl_get_file_id (fd, &id))) - { - errstring = N_("cannot stat shared object"); - lose_errno: - errval = errno; - lose: - /* The file might already be closed. */ - if (fd != -1) - __close_nocancel (fd); - if (l != NULL && l->l_map_start != 0) - _dl_unmap_segments (l); - if (l != NULL && l->l_origin != (char *) -1l) - free ((char *) l->l_origin); - if (l != NULL && !l->l_libname->dont_free) - free (l->l_libname); - if (l != NULL && l->l_phdr_allocated) - free ((void *) l->l_phdr); - free (l); - free (realname); - _dl_signal_error (errval, name, NULL, errstring); - } - - /* Look again to see if the real name matched another already loaded. */ - for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next) - if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id)) - { - /* The object is already loaded. - Just bump its reference count and return it. */ - __close_nocancel (fd); - - /* If the name is not in the list of names for this object add - it. */ - free (realname); - add_name_to_object (l, name); - - return l; - } - } - -#ifdef SHARED - /* When loading into a namespace other than the base one we must - avoid loading ld.so since there can only be one copy. Ever. */ - if (__glibc_unlikely (nsid != LM_ID_BASE) - && (_dl_file_id_match_p (&id, &GL(dl_rtld_map).l_file_id) - || _dl_name_match_p (name, &GL(dl_rtld_map)))) - { - /* This is indeed ld.so. Create a new link_map which refers to - the real one for almost everything. */ - l = _dl_new_object (realname, name, l_type, loader, mode, nsid); - if (l == NULL) - goto fail_new; - - /* Refer to the real descriptor. */ - l->l_real = &GL(dl_rtld_map); - - /* Copy l_addr and l_ld to avoid a GDB warning with dlmopen(). */ - l->l_addr = l->l_real->l_addr; - l->l_ld = l->l_real->l_ld; - - /* No need to bump the refcount of the real object, ld.so will - never be unloaded. */ - __close_nocancel (fd); - - /* Add the map for the mirrored object to the object list. */ - _dl_add_to_namespace_list (l, nsid); - - return l; - } -#endif - - if (mode & RTLD_NOLOAD) - { - /* We are not supposed to load the object unless it is already - loaded. So return now. */ - free (realname); - __close_nocancel (fd); - return NULL; - } - - /* Print debugging message. */ - if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) - _dl_debug_printf ("file=%s [%lu]; generating link map\n", name, nsid); +#define errstring (*errstring_p) +#define errval (*errval_p) /* This is the ELF header. We read it in `open_verify'. */ header = (void *) fbp->buf; - /* Enter the new object in the list of loaded objects. */ - l = _dl_new_object (realname, name, l_type, loader, mode, nsid); - if (__glibc_unlikely (l == NULL)) - { -#ifdef SHARED - fail_new: -#endif - errstring = N_("cannot create shared object descriptor"); - goto lose_errno; - } - /* Extract the remaining details we need from the ELF header and then read in the program header table. */ l->l_entry = header->e_entry; @@ -1083,7 +992,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, /* On most platforms presume that PT_GNU_STACK is absent and the stack is * executable. Other platforms default to a nonexecutable stack and don't * need PT_GNU_STACK to do so. */ - unsigned int stack_flags = DEFAULT_STACK_PERMS; + unsigned int stack_flags = DEFAULT_STACK_PERMS; { /* Scan the program header table, collecting its load commands. */ @@ -1361,30 +1270,6 @@ cannot enable executable stack as shared object requires"); if (l->l_tls_initimage != NULL) l->l_tls_initimage = (char *) l->l_tls_initimage + l->l_addr; - /* Process program headers again after load segments are mapped in - case processing requires accessing those segments. Scan program - headers backward so that PT_NOTE can be skipped if PT_GNU_PROPERTY - exits. */ - for (ph = &l->l_phdr[l->l_phnum]; ph != l->l_phdr; --ph) - switch (ph[-1].p_type) - { - case PT_NOTE: - _dl_process_pt_note (l, fd, &ph[-1]); - break; - case PT_GNU_PROPERTY: - _dl_process_pt_gnu_property (l, fd, &ph[-1]); - break; - } - - /* We are done mapping in the file. We no longer need the descriptor. */ - if (__glibc_unlikely (__close_nocancel (fd) != 0)) - { - errstring = N_("cannot close file descriptor"); - goto lose_errno; - } - /* Signal that we closed the file. */ - fd = -1; - /* Failures before this point are handled locally via lose. There are no more failures in this function until return, to change that the cleanup handling needs to be updated. */ @@ -1409,6 +1294,22 @@ cannot enable executable stack as shared object requires"); (unsigned long int) l->l_phdr, (int) sizeof (void *) * 2, l->l_phnum); + return 0; + +lose_errno: + errval = errno; +lose: + return -1; + +#undef errval +#undef errstring +} + +static void +_dl_map_object_2 (struct link_map *l, int mode, + struct r_file_id id, const char *origname, + Lmid_t nsid) +{ /* Set up the symbol hash table. */ _dl_setup_hash (l); @@ -1510,10 +1411,150 @@ cannot enable executable stack as shared object requires"); if (!GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing) _dl_audit_objopen (l, nsid); #endif +} + +/* Map in the shared object NAME, actually located in REALNAME, and already + opened on FD. */ + +#ifndef EXTERNAL_MAP_FROM_FD +static +#endif +struct link_map * +_dl_map_object_from_fd (const char *name, const char *origname, int fd, + struct filebuf *fbp, char *realname, + struct link_map *loader, int l_type, int mode, + void **stack_endp, Lmid_t nsid) +{ + struct link_map *l = NULL; + /* Initialize to keep the compiler happy. */ + const char *errstring = NULL; + int errval = 0; + + /* Get file information. To match the kernel behavior, do not fill + in this information for the executable in case of an explicit + loader invocation. */ + struct r_file_id id; + if (mode & __RTLD_OPENEXEC) + { + assert (nsid == LM_ID_BASE); + memset (&id, 0, sizeof (id)); + } + else + { + if (__glibc_unlikely (!_dl_get_file_id (fd, &id))) + { + errstring = N_("cannot stat shared object"); + lose_errno: + errval = errno; + lose: + /* The file might already be closed. */ + if (fd != -1) + __close_nocancel (fd); + if (l != NULL && l->l_map_start != 0) + _dl_unmap_segments (l); + if (l != NULL && l->l_origin != (char *) -1l) + free ((char *) l->l_origin); + if (l != NULL && !l->l_libname->dont_free) + free (l->l_libname); + if (l != NULL && l->l_phdr_allocated) + free ((void *) l->l_phdr); + free (l); + free (realname); + + _dl_signal_error (errval, name, NULL, errstring); + } + + /* Look again to see if the real name matched another already loaded. */ + for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next) + if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id)) + { + /* The object is already loaded. + Just bump its reference count and return it. */ + __close_nocancel (fd); + + /* If the name is not in the list of names for this object add + it. */ + free (realname); + add_name_to_object (l, name); + + return l; + } + } + +#ifdef SHARED + /* When loading into a namespace other than the base one we must + avoid loading ld.so since there can only be one copy. Ever. */ + if (__glibc_unlikely (nsid != LM_ID_BASE) + && (_dl_file_id_match_p (&id, &GL(dl_rtld_map).l_file_id) + || _dl_name_match_p (name, &GL(dl_rtld_map)))) + { + /* This is indeed ld.so. Create a new link_map which refers to + the real one for almost everything. */ + l = _dl_new_object (realname, name, l_type, loader, mode, nsid); + if (l == NULL) + goto fail_new; + + /* Refer to the real descriptor. */ + l->l_real = &GL(dl_rtld_map); + + /* Copy l_addr and l_ld to avoid a GDB warning with dlmopen(). */ + l->l_addr = l->l_real->l_addr; + l->l_ld = l->l_real->l_ld; + + /* No need to bump the refcount of the real object, ld.so will + never be unloaded. */ + __close_nocancel (fd); + + /* Add the map for the mirrored object to the object list. */ + _dl_add_to_namespace_list (l, nsid); + + return l; + } +#endif + + if (mode & RTLD_NOLOAD) + { + /* We are not supposed to load the object unless it is already + loaded. So return now. */ + free (realname); + __close_nocancel (fd); + return NULL; + } + + /* Print debugging message. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) + _dl_debug_printf ("file=%s [%lu]; generating link map\n", name, nsid); + + /* Enter the new object in the list of loaded objects. */ + l = _dl_new_object (realname, name, l_type, loader, mode, nsid); + if (__glibc_unlikely (l == NULL)) + { +#ifdef SHARED + fail_new: +#endif + errstring = N_("cannot create shared object descriptor"); + goto lose_errno; + } + + if (_dl_map_object_1 (l, fd, fbp, mode, loader, stack_endp, &errval, + &errstring)) + goto lose; + + _dl_process_phdrs (l, fd); + /* We are done mapping in the file. We no longer need the descriptor. */ + if (__glibc_unlikely (__close_nocancel (fd) != 0)) + { + errstring = N_("cannot close file descriptor"); + goto lose_errno; + } + /* Signal that we closed the file. */ + fd = -1; + + _dl_map_object_2 (l, mode, id, origname, nsid); return l; } - + /* Print search path. */ static void print_search_path (struct r_search_path_elem **list, From patchwork Mon Apr 3 09:04:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 67196 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3C72238708C5 for ; Mon, 3 Apr 2023 09:05:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3C72238708C5 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680512742; bh=KQjNQ+73YpTY1C0Gl8JxsFUsK+80VRwCK3l5/ZdX6A0=; 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=B7nvxAhAp6BiGbFp5GeMlb4kwbk2+ZbKNsMoUHQGhrQwRdnM2qPx1Y76dPc+uHL6H HvR8XQj3GhO7Tvovjqvn+nsF2hH7UiE07/vmdYkVL8hVLmccR283gK0FH6HrIw4f4p 17hUanG2QziDzqd98zPNPnW5j1ylMDdLtjnVjoQ8= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from forward204c.mail.yandex.net (forward204c.mail.yandex.net [178.154.239.217]) by sourceware.org (Postfix) with ESMTPS id 5BF52384D15D for ; Mon, 3 Apr 2023 09:04:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5BF52384D15D 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 EBAE9600E9 for ; Mon, 3 Apr 2023 12:04:47 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id h4J5UKjDcmI0-mTKV5sSm; Mon, 03 Apr 2023 12:04:47 +0300 X-Yandex-Fwd: 1 To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 02/12] elf: split open_verify() into reusable parts Date: Mon, 3 Apr 2023 14:04:11 +0500 Message-Id: <20230403090421.560208-3-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=-10.9 required=5.0 tests=BAYES_00, DKIM_INVALID, DKIM_SIGNED, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, GIT_PATCH_0, KAM_DMARC_STATUS, 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 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+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" This is almost a mechanical refactoring that splits open_verify() into 2 parts. The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev --- elf/dl-load.c | 337 ++++++++++++++++++++++++++------------------------ 1 file changed, 175 insertions(+), 162 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index 6b2c3ac6bf..7a939cb8c1 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1596,19 +1596,11 @@ print_search_path (struct r_search_path_elem **list, else _dl_debug_printf_c ("\t\t(%s)\n", what); } - -/* Open a file and verify it is an ELF file for this architecture. We - ignore only ELF files for other architectures. Non-ELF files and - ELF files with different header information cause fatal errors since - this could mean there is something wrong in the installation and the - user might want to know about this. - If FD is not -1, then the file is already open and FD refers to it. - In that case, FD is consumed for both successful and error returns. */ static int -open_verify (const char *name, int fd, - struct filebuf *fbp, struct link_map *loader, - int whatcode, int mode, bool *found_other_class, bool free_name) +do_open_verify (const char *name, int fd, + struct filebuf *fbp, struct link_map *loader, + bool *found_other_class, bool free_name) { /* This is the expected ELF header. */ #define ELF32_CLASS ELFCLASS32 @@ -1635,7 +1627,170 @@ open_verify (const char *name, int fd, /* Initialize it to make the compiler happy. */ const char *errstring = NULL; int errval = 0; + ElfW(Ehdr) *ehdr; + ElfW(Phdr) *phdr; + size_t maplength; + + /* We successfully opened the file. Now verify it is a file + we can use. */ + __set_errno (0); + fbp->len = 0; + assert (sizeof (fbp->buf) > sizeof (ElfW(Ehdr))); + /* Read in the header. */ + do + { + ssize_t retlen = __read_nocancel (fd, fbp->buf + fbp->len, + sizeof (fbp->buf) - fbp->len); + if (retlen <= 0) + break; + fbp->len += retlen; + } + while (__glibc_unlikely (fbp->len < sizeof (ElfW(Ehdr)))); + + /* This is where the ELF header is loaded. */ + ehdr = (ElfW(Ehdr) *) fbp->buf; + + /* Now run the tests. */ + if (__glibc_unlikely (fbp->len < (ssize_t) sizeof (ElfW(Ehdr)))) + { + errval = errno; + errstring = (errval == 0 + ? N_("file too short") : N_("cannot read file data")); + lose: + if (free_name) + { + char *realname = (char *) name; + name = strdupa (realname); + free (realname); + } + _dl_signal_error (errval, name, NULL, errstring); + return -1; + } + + /* See whether the ELF header is what we expect. */ + if (__glibc_unlikely (! VALID_ELF_HEADER (ehdr->e_ident, expected, + EI_ABIVERSION) + || !VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI], + ehdr->e_ident[EI_ABIVERSION]) + || memcmp (&ehdr->e_ident[EI_PAD], + &expected[EI_PAD], + EI_NIDENT - EI_PAD) != 0)) + { + /* Something is wrong. */ + const Elf32_Word *magp = (const void *) ehdr->e_ident; + if (*magp != +#if BYTE_ORDER == LITTLE_ENDIAN + ((ELFMAG0 << (EI_MAG0 * 8)) + | (ELFMAG1 << (EI_MAG1 * 8)) + | (ELFMAG2 << (EI_MAG2 * 8)) + | (ELFMAG3 << (EI_MAG3 * 8))) +#else + ((ELFMAG0 << (EI_MAG3 * 8)) + | (ELFMAG1 << (EI_MAG2 * 8)) + | (ELFMAG2 << (EI_MAG1 * 8)) + | (ELFMAG3 << (EI_MAG0 * 8))) +#endif + ) + errstring = N_("invalid ELF header"); + + else if (ehdr->e_ident[EI_CLASS] != ELFW(CLASS)) + { + /* This is not a fatal error. On architectures where + 32-bit and 64-bit binaries can be run this might + happen. */ + *found_other_class = true; + __set_errno (ENOENT); + return -1; + } + else if (ehdr->e_ident[EI_DATA] != byteorder) + { + if (BYTE_ORDER == BIG_ENDIAN) + errstring = N_("ELF file data encoding not big-endian"); + else + errstring = N_("ELF file data encoding not little-endian"); + } + else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) + errstring + = N_("ELF file version ident does not match current one"); + /* XXX We should be able so set system specific versions which are + allowed here. */ + else if (!VALID_ELF_OSABI (ehdr->e_ident[EI_OSABI])) + errstring = N_("ELF file OS ABI invalid"); + else if (!VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI], + ehdr->e_ident[EI_ABIVERSION])) + errstring = N_("ELF file ABI version invalid"); + else if (memcmp (&ehdr->e_ident[EI_PAD], &expected[EI_PAD], + EI_NIDENT - EI_PAD) != 0) + errstring = N_("nonzero padding in e_ident"); + else + /* Otherwise we don't know what went wrong. */ + errstring = N_("internal error"); + + goto lose; + } + + if (__glibc_unlikely (ehdr->e_version != EV_CURRENT)) + { + errstring = N_("ELF file version does not match current one"); + goto lose; + } + if (! __glibc_likely (elf_machine_matches_host (ehdr))) + { + __set_errno (ENOENT); + return -1; + } + else if (__glibc_unlikely (ehdr->e_type != ET_DYN + && ehdr->e_type != ET_EXEC)) + { + errstring = N_("only ET_DYN and ET_EXEC can be loaded"); + goto lose; + } + else if (__glibc_unlikely (ehdr->e_phentsize != sizeof (ElfW(Phdr)))) + { + errstring = N_("ELF file's phentsize not the expected size"); + goto lose; + } + + maplength = ehdr->e_phnum * sizeof (ElfW(Phdr)); + if (ehdr->e_phoff + maplength <= (size_t) fbp->len) + phdr = (void *) (fbp->buf + ehdr->e_phoff); + else + { + phdr = alloca (maplength); + if ((size_t) __pread64_nocancel (fd, (void *) phdr, maplength, + ehdr->e_phoff) != maplength) + { + errval = errno; + errstring = N_("cannot read file data"); + goto lose; + } + } + + if (__glibc_unlikely (elf_machine_reject_phdr_p + (phdr, ehdr->e_phnum, fbp->buf, fbp->len, + loader, -1))) + { + __set_errno (ENOENT); + return -1; + } + + return 0; +} + + +/* Open a file and verify it is an ELF file for this architecture. We + ignore only ELF files for other architectures. Non-ELF files and + ELF files with different header information cause fatal errors since + this could mean there is something wrong in the installation and the + user might want to know about this. + If FD is not -1, then the file is already open and FD refers to it. + In that case, FD is consumed for both successful and error returns. */ +static int +open_verify (const char *name, int fd, + struct filebuf *fbp, struct link_map *loader, + int whatcode, int mode, bool *found_other_class, bool free_name) +{ #ifdef SHARED /* Give the auditing libraries a chance. */ if (__glibc_unlikely (GLRO(dl_naudit) > 0)) @@ -1661,161 +1816,19 @@ open_verify (const char *name, int fd, if (fd != -1) { - ElfW(Ehdr) *ehdr; - ElfW(Phdr) *phdr; - size_t maplength; - - /* We successfully opened the file. Now verify it is a file - we can use. */ - __set_errno (0); - fbp->len = 0; - assert (sizeof (fbp->buf) > sizeof (ElfW(Ehdr))); - /* Read in the header. */ - do - { - ssize_t retlen = __read_nocancel (fd, fbp->buf + fbp->len, - sizeof (fbp->buf) - fbp->len); - if (retlen <= 0) - break; - fbp->len += retlen; - } - while (__glibc_unlikely (fbp->len < sizeof (ElfW(Ehdr)))); - - /* This is where the ELF header is loaded. */ - ehdr = (ElfW(Ehdr) *) fbp->buf; - - /* Now run the tests. */ - if (__glibc_unlikely (fbp->len < (ssize_t) sizeof (ElfW(Ehdr)))) - { - errval = errno; - errstring = (errval == 0 - ? N_("file too short") : N_("cannot read file data")); - lose: - if (free_name) - { - char *realname = (char *) name; - name = strdupa (realname); - free (realname); - } - __close_nocancel (fd); - _dl_signal_error (errval, name, NULL, errstring); - } - - /* See whether the ELF header is what we expect. */ - if (__glibc_unlikely (! VALID_ELF_HEADER (ehdr->e_ident, expected, - EI_ABIVERSION) - || !VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI], - ehdr->e_ident[EI_ABIVERSION]) - || memcmp (&ehdr->e_ident[EI_PAD], - &expected[EI_PAD], - EI_NIDENT - EI_PAD) != 0)) - { - /* Something is wrong. */ - const Elf32_Word *magp = (const void *) ehdr->e_ident; - if (*magp != -#if BYTE_ORDER == LITTLE_ENDIAN - ((ELFMAG0 << (EI_MAG0 * 8)) - | (ELFMAG1 << (EI_MAG1 * 8)) - | (ELFMAG2 << (EI_MAG2 * 8)) - | (ELFMAG3 << (EI_MAG3 * 8))) -#else - ((ELFMAG0 << (EI_MAG3 * 8)) - | (ELFMAG1 << (EI_MAG2 * 8)) - | (ELFMAG2 << (EI_MAG1 * 8)) - | (ELFMAG3 << (EI_MAG0 * 8))) -#endif - ) - errstring = N_("invalid ELF header"); - - else if (ehdr->e_ident[EI_CLASS] != ELFW(CLASS)) - { - /* This is not a fatal error. On architectures where - 32-bit and 64-bit binaries can be run this might - happen. */ - *found_other_class = true; - __close_nocancel (fd); - __set_errno (ENOENT); - return -1; - } - else if (ehdr->e_ident[EI_DATA] != byteorder) - { - if (BYTE_ORDER == BIG_ENDIAN) - errstring = N_("ELF file data encoding not big-endian"); - else - errstring = N_("ELF file data encoding not little-endian"); - } - else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) - errstring - = N_("ELF file version ident does not match current one"); - /* XXX We should be able so set system specific versions which are - allowed here. */ - else if (!VALID_ELF_OSABI (ehdr->e_ident[EI_OSABI])) - errstring = N_("ELF file OS ABI invalid"); - else if (!VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI], - ehdr->e_ident[EI_ABIVERSION])) - errstring = N_("ELF file ABI version invalid"); - else if (memcmp (&ehdr->e_ident[EI_PAD], &expected[EI_PAD], - EI_NIDENT - EI_PAD) != 0) - errstring = N_("nonzero padding in e_ident"); - else - /* Otherwise we don't know what went wrong. */ - errstring = N_("internal error"); - - goto lose; - } - - if (__glibc_unlikely (ehdr->e_version != EV_CURRENT)) - { - errstring = N_("ELF file version does not match current one"); - goto lose; - } - if (! __glibc_likely (elf_machine_matches_host (ehdr))) - { - __close_nocancel (fd); - __set_errno (ENOENT); - return -1; - } - else if (__glibc_unlikely (ehdr->e_type != ET_DYN - && ehdr->e_type != ET_EXEC)) - { - errstring = N_("only ET_DYN and ET_EXEC can be loaded"); - goto lose; - } - else if (__glibc_unlikely (ehdr->e_phentsize != sizeof (ElfW(Phdr)))) - { - errstring = N_("ELF file's phentsize not the expected size"); - goto lose; - } - - maplength = ehdr->e_phnum * sizeof (ElfW(Phdr)); - if (ehdr->e_phoff + maplength <= (size_t) fbp->len) - phdr = (void *) (fbp->buf + ehdr->e_phoff); - else - { - phdr = alloca (maplength); - if ((size_t) __pread64_nocancel (fd, (void *) phdr, maplength, - ehdr->e_phoff) != maplength) - { - errval = errno; - errstring = N_("cannot read file data"); - goto lose; - } - } - - if (__glibc_unlikely (elf_machine_reject_phdr_p - (phdr, ehdr->e_phnum, fbp->buf, fbp->len, - loader, fd))) - { - __close_nocancel (fd); - __set_errno (ENOENT); - return -1; - } - + int err = do_open_verify (name, fd, fbp, loader, + found_other_class, + free_name); + if (err) + { + __close_nocancel (fd); + return -1; + } } return fd; } - + /* Try to open NAME in one of the directories in *DIRSP. Return the fd, or -1. If successful, fill in *REALNAME with the malloc'd full directory name. If it turns out From patchwork Mon Apr 3 09:04:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 67195 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5A18838515DB for ; Mon, 3 Apr 2023 09:05:13 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5A18838515DB DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680512713; bh=117cSdAW89ebS80ru56peSq5GRcbYMjuvkjReW4Hdm0=; 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=MN+R3WvxKM2PpLL77EcK1oLFIctX8DojcYO9mVQznhGSi9BH4bt0yeDArdYWGZpA1 EbxnMkNcnhN6zDIeVxIePZ+ZaIYRMdNgvmCRHK7uPqLdJY3lahTppp5H1lRYwTujJY MpEbo2BpMoXrO64ZRTZGZCDzC6poTYrDlNXrC3+4= 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 1C0BD3850218 for ; Mon, 3 Apr 2023 09:04:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1C0BD3850218 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 D408360102 for ; Mon, 3 Apr 2023 12:04:48 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id h4J5UKjDcmI0-JGuoInyj; Mon, 03 Apr 2023 12:04:48 +0300 X-Yandex-Fwd: 1 To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 03/12] elf: split _dl_check_loaded() from _dl_map_object Date: Mon, 3 Apr 2023 14:04:12 +0500 Message-Id: <20230403090421.560208-4-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.3 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+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" This is a purely mechanical split of a reusable code part. No functional changes. The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev --- elf/dl-load.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index 7a939cb8c1..e05a2a41de 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1988,23 +1988,11 @@ open_path (const char *name, size_t namelen, int mode, return -1; } -/* Map in the shared object file NAME. */ - -struct link_map * -_dl_map_object (struct link_map *loader, const char *name, - int type, int trace_mode, int mode, Lmid_t nsid) +static struct link_map * +_dl_check_loaded(const char *name, Lmid_t nsid) { - int fd; - const char *origname = NULL; - char *realname; - char *name_copy; struct link_map *l; - struct filebuf fb; - - assert (nsid >= 0); - assert (nsid < GL(dl_nns)); - /* Look for this name among those already loaded. */ for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next) { /* If the requested name matches the soname of a loaded object, @@ -2033,6 +2021,29 @@ _dl_map_object (struct link_map *loader, const char *name, /* We have a match. */ return l; } + return NULL; +} + +/* Map in the shared object file NAME. */ + +struct link_map * +_dl_map_object (struct link_map *loader, const char *name, + int type, int trace_mode, int mode, Lmid_t nsid) +{ + int fd; + const char *origname = NULL; + char *realname; + char *name_copy; + struct link_map *l; + struct filebuf fb; + + assert (nsid >= 0); + assert (nsid < GL(dl_nns)); + + /* Look for this name among those already loaded. */ + l = _dl_check_loaded (name, nsid); + if (l) + return l; /* Display information if we are debugging. */ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES) From patchwork Mon Apr 3 09:04:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 67199 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C9E79388202E for ; Mon, 3 Apr 2023 09:07:01 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C9E79388202E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680512821; bh=lIuZH+Sh5GbEbgelv51hMCxfCZ93nzsDtFczm9+RhCg=; 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=P2ZfsMOsTSDITJcAygvoocLc9G/EzO6qBBoMFmMORrJJF2qUcIm9R9EA8K2YOimEN 33FOF5mG2l2gapE6D5qiiMV8+OwXwAtI9PAwbQTTMu3TLbnjBg75cAy3VJqNnitZ7N FWf0pniGheZ23zCIsJyOZekQ4DPPVR3bqApWALXU= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from forward201b.mail.yandex.net (forward201b.mail.yandex.net [IPv6:2a02:6b8:c02:900:1:45:d181:d201]) by sourceware.org (Postfix) with ESMTPS id 0D82638582A4 for ; Mon, 3 Apr 2023 09:04:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0D82638582A4 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 forward201b.mail.yandex.net (Yandex) with ESMTP id D9AE446D04 for ; Mon, 3 Apr 2023 12:04:49 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id h4J5UKjDcmI0-2zN3K4n7; Mon, 03 Apr 2023 12:04:49 +0300 X-Yandex-Fwd: 1 To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 04/12] elf: load elf hdr fully in open_verify() Date: Mon, 3 Apr 2023 14:04:13 +0500 Message-Id: <20230403090421.560208-5-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=-10.9 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+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" open_verify() reads an elf header, putting only the ehdr part into the filebuf, and reading the rest of the header into the alloca() space. This requires _ld_map_object_1() (former _ld_map_object_from_fd()) to read parts of an elf header again, getting only ehdr from filebuf. This patch makes filebuf sizeable and reads an entire elf header there, avoiding the code duplication and getting rid of file reads in _ld_map_object_1(). The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev --- elf/dl-load.c | 122 +++++++++++++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 56 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index e05a2a41de..2099a09c80 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -55,7 +55,8 @@ struct filebuf #else # define FILEBUF_SIZE 832 #endif - char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr))))); + ssize_t allocated; + char *buf; }; #include "dynamic-link.h" @@ -124,6 +125,29 @@ static const size_t system_dirs_len[] = }; #define nsystem_dirs_len array_length (system_dirs_len) +static void +filebuf_done (struct filebuf *fb) +{ + free (fb->buf); + fb->buf = NULL; + fb->allocated = 0; +} + +static bool +filebuf_ensure (struct filebuf *fb, size_t size) +{ + bool ret = false; + + if (size > fb->allocated) + { + size_t new_len = size + FILEBUF_SIZE; + fb->buf = realloc (fb->buf, new_len); + fb->allocated = new_len; + ret = true; + } + return ret; +} + static bool is_trusted_path_normalize (const char *path, size_t len) { @@ -976,18 +1000,8 @@ _dl_map_object_1 (struct link_map *l, int fd, l->l_phnum = header->e_phnum; maplength = header->e_phnum * sizeof (ElfW(Phdr)); - if (header->e_phoff + maplength <= (size_t) fbp->len) - phdr = (void *) (fbp->buf + header->e_phoff); - else - { - phdr = alloca (maplength); - if ((size_t) __pread64_nocancel (fd, (void *) phdr, maplength, - header->e_phoff) != maplength) - { - errstring = N_("cannot read file data"); - goto lose_errno; - } - } + assert (header->e_phoff + maplength <= (size_t) fbp->len); + phdr = (void *) (fbp->buf + header->e_phoff); /* On most platforms presume that PT_GNU_STACK is absent and the stack is * executable. Other platforms default to a nonexecutable stack and don't @@ -1627,31 +1641,16 @@ do_open_verify (const char *name, int fd, /* Initialize it to make the compiler happy. */ const char *errstring = NULL; int errval = 0; - ElfW(Ehdr) *ehdr; + ElfW(Ehdr) _ehdr; + ElfW(Ehdr) *ehdr = &_ehdr; ElfW(Phdr) *phdr; size_t maplength; /* We successfully opened the file. Now verify it is a file we can use. */ __set_errno (0); - fbp->len = 0; - assert (sizeof (fbp->buf) > sizeof (ElfW(Ehdr))); /* Read in the header. */ - do - { - ssize_t retlen = __read_nocancel (fd, fbp->buf + fbp->len, - sizeof (fbp->buf) - fbp->len); - if (retlen <= 0) - break; - fbp->len += retlen; - } - while (__glibc_unlikely (fbp->len < sizeof (ElfW(Ehdr)))); - - /* This is where the ELF header is loaded. */ - ehdr = (ElfW(Ehdr) *) fbp->buf; - - /* Now run the tests. */ - if (__glibc_unlikely (fbp->len < (ssize_t) sizeof (ElfW(Ehdr)))) + if (__pread64_nocancel (fd, &_ehdr, sizeof(_ehdr), 0) != sizeof(_ehdr)) { errval = errno; errstring = (errval == 0 @@ -1752,19 +1751,17 @@ do_open_verify (const char *name, int fd, } maplength = ehdr->e_phnum * sizeof (ElfW(Phdr)); - if (ehdr->e_phoff + maplength <= (size_t) fbp->len) - phdr = (void *) (fbp->buf + ehdr->e_phoff); - else + filebuf_ensure (fbp, maplength + ehdr->e_phoff); + if ((size_t) __pread64_nocancel (fd, fbp->buf, maplength + + ehdr->e_phoff, 0) != maplength + + ehdr->e_phoff) { - phdr = alloca (maplength); - if ((size_t) __pread64_nocancel (fd, (void *) phdr, maplength, - ehdr->e_phoff) != maplength) - { - errval = errno; - errstring = N_("cannot read file data"); - goto lose; - } + errval = errno; + errstring = N_("cannot read file data"); + goto lose; } + fbp->len = maplength + ehdr->e_phoff; + phdr = (void *) (fbp->buf + ehdr->e_phoff); if (__glibc_unlikely (elf_machine_reject_phdr_p (phdr, ehdr->e_phnum, fbp->buf, fbp->len, @@ -2026,16 +2023,16 @@ _dl_check_loaded(const char *name, Lmid_t nsid) /* Map in the shared object file NAME. */ -struct link_map * -_dl_map_object (struct link_map *loader, const char *name, - int type, int trace_mode, int mode, Lmid_t nsid) +static struct link_map * +___dl_map_object (struct link_map *loader, const char *name, + int type, int trace_mode, int mode, Lmid_t nsid, + struct filebuf *fbp) { int fd; const char *origname = NULL; char *realname; char *name_copy; struct link_map *l; - struct filebuf fb; assert (nsid >= 0); assert (nsid < GL(dl_nns)); @@ -2100,7 +2097,7 @@ _dl_map_object (struct link_map *loader, const char *name, { fd = open_path (name, namelen, mode, &l->l_rpath_dirs, - &realname, &fb, loader, LA_SER_RUNPATH, + &realname, fbp, loader, LA_SER_RUNPATH, &found_other_class); if (fd != -1) break; @@ -2116,7 +2113,7 @@ _dl_map_object (struct link_map *loader, const char *name, "RPATH")) fd = open_path (name, namelen, mode, &main_map->l_rpath_dirs, - &realname, &fb, loader ?: main_map, LA_SER_RUNPATH, + &realname, fbp, loader ?: main_map, LA_SER_RUNPATH, &found_other_class); /* Also try DT_RUNPATH in the executable for LD_AUDIT dlopen @@ -2130,7 +2127,7 @@ _dl_map_object (struct link_map *loader, const char *name, if (cache_rpath (main_map, &l_rpath_dirs, DT_RUNPATH, "RUNPATH")) fd = open_path (name, namelen, mode, &l_rpath_dirs, - &realname, &fb, loader ?: main_map, + &realname, fbp, loader ?: main_map, LA_SER_RUNPATH, &found_other_class); } } @@ -2138,7 +2135,7 @@ _dl_map_object (struct link_map *loader, const char *name, /* Try the LD_LIBRARY_PATH environment variable. */ if (fd == -1 && __rtld_env_path_list.dirs != (void *) -1) fd = open_path (name, namelen, mode, &__rtld_env_path_list, - &realname, &fb, + &realname, fbp, loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded, LA_SER_LIBPATH, &found_other_class); @@ -2147,7 +2144,7 @@ _dl_map_object (struct link_map *loader, const char *name, && cache_rpath (loader, &loader->l_runpath_dirs, DT_RUNPATH, "RUNPATH")) fd = open_path (name, namelen, mode, - &loader->l_runpath_dirs, &realname, &fb, loader, + &loader->l_runpath_dirs, &realname, fbp, loader, LA_SER_RUNPATH, &found_other_class); if (fd == -1) @@ -2156,7 +2153,7 @@ _dl_map_object (struct link_map *loader, const char *name, if (realname != NULL) { fd = open_verify (realname, fd, - &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, + fbp, loader ?: GL(dl_ns)[nsid]._ns_loaded, LA_SER_CONFIG, mode, &found_other_class, false); if (fd == -1) @@ -2210,7 +2207,7 @@ _dl_map_object (struct link_map *loader, const char *name, if (cached != NULL) { fd = open_verify (cached, -1, - &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, + fbp, loader ?: GL(dl_ns)[nsid]._ns_loaded, LA_SER_CONFIG, mode, &found_other_class, false); if (__glibc_likely (fd != -1)) @@ -2228,7 +2225,7 @@ _dl_map_object (struct link_map *loader, const char *name, || __glibc_likely (!(l->l_flags_1 & DF_1_NODEFLIB))) && __rtld_search_dirs.dirs != (void *) -1) fd = open_path (name, namelen, mode, &__rtld_search_dirs, - &realname, &fb, l, LA_SER_DEFAULT, &found_other_class); + &realname, fbp, l, LA_SER_DEFAULT, &found_other_class); /* Add another newline when we are tracing the library loading. */ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) @@ -2244,7 +2241,7 @@ _dl_map_object (struct link_map *loader, const char *name, fd = -1; else { - fd = open_verify (realname, -1, &fb, + fd = open_verify (realname, -1, fbp, loader ?: GL(dl_ns)[nsid]._ns_loaded, 0, mode, &found_other_class, true); if (__glibc_unlikely (fd == -1)) @@ -2305,10 +2302,23 @@ _dl_map_object (struct link_map *loader, const char *name, } void *stack_end = __libc_stack_end; - return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader, + return _dl_map_object_from_fd (name, origname, fd, fbp, realname, loader, type, mode, &stack_end, nsid); } +struct link_map * +_dl_map_object (struct link_map *loader, const char *name, + int type, int trace_mode, + int mode, Lmid_t nsid) +{ + struct link_map *ret; + struct filebuf fb = {}; + + ret = ___dl_map_object (loader, name, type, trace_mode, mode, nsid, &fb); + filebuf_done (&fb); + return ret; +} + struct add_path_state { bool counting; From patchwork Mon Apr 3 09:04:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 67198 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 28EA43870885 for ; Mon, 3 Apr 2023 09:06:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 28EA43870885 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680512809; bh=ojwUt2nxnDCDYWu8PbuC4JeZ5jvgGam+dt4jwa4sLZc=; 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=Uen09Fv8Q/0lvdkywSN27dqwMmvMDv8o+eTcoEgsx7cFgsYZQ1NQ1Q+Z06QH3kuvU bA3Hz7ZgIKQtJJUJQFqXNHEyRW0dcYuJKP7xpyRa3NOgqGNIb4G2DVfGmeuNUXd1de SJ/acIfCERHnIkbJx0xhTcWg1qg7GyBUMRQGCC0A= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from forward203b.mail.yandex.net (forward203b.mail.yandex.net [IPv6:2a02:6b8:c02:900:1:45:d181:d203]) by sourceware.org (Postfix) with ESMTPS id 8F56438582AC for ; Mon, 3 Apr 2023 09:04:52 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8F56438582AC 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 forward203b.mail.yandex.net (Yandex) with ESMTP id 19061600EF for ; Mon, 3 Apr 2023 12:04:51 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id h4J5UKjDcmI0-eRUnnPt1; Mon, 03 Apr 2023 12:04:50 +0300 X-Yandex-Fwd: 1 To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 05/12] elf: switch _dl_map_segment() to anonymous mapping Date: Mon, 3 Apr 2023 14:04:14 +0500 Message-Id: <20230403090421.560208-6-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=-10.9 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+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" _dl_map_segment() was mapping entire file image and then was skipping the load of the first segment. Switch _dl_map_segment() to anonymous mapping and do not skip the map of the first segment. Use PROT_READ|PROT_WRITE as a protection. _dl_map_segments() later sets the proper protection for both file-mapped and anonymous parts. The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev --- elf/dl-map-segments.h | 69 ++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h index 504cfc0a41..ed7675cabf 100644 --- a/elf/dl-map-segments.h +++ b/elf/dl-map-segments.h @@ -22,18 +22,22 @@ /* Map a segment and align it properly. */ static __always_inline ElfW(Addr) -_dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref, - const size_t maplength, int fd) +_dl_map_segment (ElfW(Addr) mappref, size_t maplength, size_t mapalign) { - if (__glibc_likely (c->mapalign <= GLRO(dl_pagesize))) - return (ElfW(Addr)) __mmap ((void *) mappref, maplength, c->prot, - MAP_COPY|MAP_FILE, fd, c->mapoff); + int err; + /* MAP_COPY is a special flag combination for solibs. */ + unsigned int map_flags = MAP_ANONYMOUS | MAP_COPY; + unsigned int prot = PROT_READ | PROT_WRITE; + + if (__glibc_likely (mapalign <= GLRO(dl_pagesize))) + return (ElfW(Addr)) __mmap ((void *) mappref, maplength, prot, + map_flags, -1, 0); /* If the segment alignment > the page size, allocate enough space to ensure that the segment can be properly aligned. */ - ElfW(Addr) maplen = (maplength >= c->mapalign - ? (maplength + c->mapalign) - : (2 * c->mapalign)); + ElfW(Addr) maplen = (maplength >= mapalign + ? (maplength + mapalign) + : (2 * mapalign)); ElfW(Addr) map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplen, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, @@ -41,26 +45,24 @@ _dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref, if (__glibc_unlikely ((void *) map_start == MAP_FAILED)) return map_start; - ElfW(Addr) map_start_aligned = ALIGN_UP (map_start, c->mapalign); - map_start_aligned = (ElfW(Addr)) __mmap ((void *) map_start_aligned, - maplength, c->prot, - MAP_COPY|MAP_FILE|MAP_FIXED, - fd, c->mapoff); - if (__glibc_unlikely ((void *) map_start_aligned == MAP_FAILED)) - __munmap ((void *) map_start, maplen); - else + ElfW(Addr) map_start_aligned = ALIGN_UP (map_start, mapalign); + err = __mprotect ((void *) map_start_aligned, maplength, prot); + if (__glibc_unlikely (err)) { - /* Unmap the unused regions. */ - ElfW(Addr) delta = map_start_aligned - map_start; - if (delta) - __munmap ((void *) map_start, delta); - ElfW(Addr) map_end = map_start_aligned + maplength; - map_end = ALIGN_UP (map_end, GLRO(dl_pagesize)); - delta = map_start + maplen - map_end; - if (delta) - __munmap ((void *) map_end, delta); + __munmap ((void *) map_start, maplen); + return (ElfW(Addr)) MAP_FAILED; } + /* Unmap the unused regions. */ + ElfW(Addr) delta = map_start_aligned - map_start; + if (delta) + __munmap ((void *) map_start, delta); + ElfW(Addr) map_end = map_start_aligned + maplength; + map_end = ALIGN_UP (map_end, GLRO(dl_pagesize)); + delta = map_start + maplen - map_end; + if (delta) + __munmap ((void *) map_end, delta); + return map_start_aligned; } @@ -98,7 +100,7 @@ _dl_map_segments (struct link_map *l, int fd, - MAP_BASE_ADDR (l)); /* Remember which part of the address space this object uses. */ - l->l_map_start = _dl_map_segment (c, mappref, maplength, fd); + l->l_map_start = _dl_map_segment (mappref, maplength, c->mapalign); if (__glibc_unlikely ((void *) l->l_map_start == MAP_FAILED)) return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; @@ -123,14 +125,14 @@ _dl_map_segments (struct link_map *l, int fd, } l->l_contiguous = 1; - - goto postmap; } - - /* Remember which part of the address space this object uses. */ - l->l_map_start = c->mapstart + l->l_addr; - l->l_map_end = l->l_map_start + maplength; - l->l_contiguous = !has_holes; + else + { + /* Remember which part of the address space this object uses. */ + l->l_map_start = c->mapstart + l->l_addr; + l->l_map_end = l->l_map_start + maplength; + l->l_contiguous = !has_holes; + } while (c < &loadcmds[nloadcmds]) { @@ -143,7 +145,6 @@ _dl_map_segments (struct link_map *l, int fd, == MAP_FAILED)) return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; - postmap: _dl_postprocess_loadcmd (l, header, c); if (c->allocend > c->dataend) From patchwork Mon Apr 3 09:04:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 67200 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8033C384F02C for ; Mon, 3 Apr 2023 09:07:16 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8033C384F02C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680512836; bh=hkbJtU5vOkPSxy6tsjsf5MRVjjru+Q+i24dp350Gslo=; 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=c4pBje8qxRkgo4FSgGdqW0q8SQgb41KB4Q8Ik0/vG7QEZHShJpArp6rZ5oBazSWc/ lgIhGgHAkfvpTjPbpHG7epLRdg8Cm74jCi73vI6ZRAtuY0Yhjz2husaj72amc+6TZF N5R6dL1uifJfzL3HqTVOvOk7CVmULTAr29J+Xxc0= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from forward101c.mail.yandex.net (forward101c.mail.yandex.net [IPv6:2a02:6b8:c03:500:1:45:d181:d101]) by sourceware.org (Postfix) with ESMTPS id 7FFC83843851 for ; Mon, 3 Apr 2023 09:04:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7FFC83843851 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 forward101c.mail.yandex.net (Yandex) with ESMTP id 6384260111 for ; Mon, 3 Apr 2023 12:04:52 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id h4J5UKjDcmI0-HnqCN0Ln; Mon, 03 Apr 2023 12:04:51 +0300 X-Yandex-Fwd: 1 To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 06/12] elf: convert pread64 to callback in do_open_verify() Date: Mon, 3 Apr 2023 14:04:15 +0500 Message-Id: <20230403090421.560208-7-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.0 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+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" This unbinds do_open_verify() from fd. The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev --- elf/dl-load.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index 2099a09c80..ceafaa4228 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1611,10 +1611,18 @@ print_search_path (struct r_search_path_elem **list, _dl_debug_printf_c ("\t\t(%s)\n", what); } +static ssize_t +do_pread (void *arg, void *buf, size_t count, off_t offset) +{ + int fd = *(const int *) arg; + return __pread64_nocancel (fd, buf, count, offset); +} + static int -do_open_verify (const char *name, int fd, +do_open_verify (const char *name, void *fd, struct filebuf *fbp, struct link_map *loader, - bool *found_other_class, bool free_name) + bool *found_other_class, bool free_name, + __typeof (do_pread) *pread_cb) { /* This is the expected ELF header. */ #define ELF32_CLASS ELFCLASS32 @@ -1650,7 +1658,7 @@ do_open_verify (const char *name, int fd, we can use. */ __set_errno (0); /* Read in the header. */ - if (__pread64_nocancel (fd, &_ehdr, sizeof(_ehdr), 0) != sizeof(_ehdr)) + if (pread_cb (fd, &_ehdr, sizeof(_ehdr), 0) != sizeof(_ehdr)) { errval = errno; errstring = (errval == 0 @@ -1752,7 +1760,7 @@ do_open_verify (const char *name, int fd, maplength = ehdr->e_phnum * sizeof (ElfW(Phdr)); filebuf_ensure (fbp, maplength + ehdr->e_phoff); - if ((size_t) __pread64_nocancel (fd, fbp->buf, maplength + + if ((size_t) pread_cb (fd, fbp->buf, maplength + ehdr->e_phoff, 0) != maplength + ehdr->e_phoff) { @@ -1813,9 +1821,9 @@ open_verify (const char *name, int fd, if (fd != -1) { - int err = do_open_verify (name, fd, fbp, loader, + int err = do_open_verify (name, &fd, fbp, loader, found_other_class, - free_name); + free_name, do_pread); if (err) { __close_nocancel (fd); From patchwork Mon Apr 3 09:04:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 67201 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 367B83882AFA for ; Mon, 3 Apr 2023 09:07:30 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 367B83882AFA DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680512850; bh=jB1rA5oNqXQ+/vxivD9ixS3nsMbenl7DpUOr/Ukanmc=; 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=EeYaiTwmhFx8d4BazSRcIjY2dQ6yuBzimsvXx+g+4dkGzA3OGAT3gmFzGPWX5iy8R cEiNb0DGxyHfzRSMipmW8aWUoj9BxvooWIQl/uEAeOF9aZRFWuncZ72A1BOZe2+GgP wv0VncAVHe77X8zQ9ECnNVnIHClH7yewA5jZSBoU= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from forward206c.mail.yandex.net (forward206c.mail.yandex.net [IPv6:2a02:6b8:c03:500:1:45:d181:d206]) by sourceware.org (Postfix) with ESMTPS id B69AC38768B4 for ; Mon, 3 Apr 2023 09:04:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B69AC38768B4 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 forward206c.mail.yandex.net (Yandex) with ESMTP id 6040E60105 for ; Mon, 3 Apr 2023 12:04:53 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id h4J5UKjDcmI0-wM8eKCXN; Mon, 03 Apr 2023 12:04:52 +0300 X-Yandex-Fwd: 1 To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 07/12] elf: convert _dl_map_segments's mmap() to a callback Date: Mon, 3 Apr 2023 14:04:16 +0500 Message-Id: <20230403090421.560208-8-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.1 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+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" This only applies to file-based mmap. Since _dl_map_segment() was converted to anonymous mmap, only 1 place is now converted to a callback. The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev --- elf/dl-load.c | 19 ++++++++++++++----- elf/dl-load.h | 8 ++++++-- elf/dl-map-segments.h | 6 +++--- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index ceafaa4228..c0704dc89c 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -975,11 +975,12 @@ _dl_process_phdrs (struct link_map *l, int fd) } static int -_dl_map_object_1 (struct link_map *l, int fd, +_dl_map_object_1 (struct link_map *l, void *fd, struct filebuf *fbp, int mode, struct link_map *loader, void **stack_endp, int *errval_p, - const char **errstring_p) + const char **errstring_p, + __typeof (do_mmap) *m_map) { const ElfW(Ehdr) *header; const ElfW(Phdr) *phdr; @@ -1179,7 +1180,7 @@ _dl_map_object_1 (struct link_map *l, int fd, l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr */ errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds, - maplength, has_holes, loader); + maplength, has_holes, loader, m_map); if (__glibc_unlikely (errstring != NULL)) { /* Mappings can be in an inconsistent state: avoid unmap. */ @@ -1430,6 +1431,14 @@ _dl_map_object_2 (struct link_map *l, int mode, /* Map in the shared object NAME, actually located in REALNAME, and already opened on FD. */ +static void * +do_mmap (void *addr, size_t length, int prot, int flags, + void *arg, off_t offset) +{ + int fd = arg ? *(const int *) arg : -1; + return __mmap (addr, length, prot, flags, fd, offset); +} + #ifndef EXTERNAL_MAP_FROM_FD static #endif @@ -1550,8 +1559,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, goto lose_errno; } - if (_dl_map_object_1 (l, fd, fbp, mode, loader, stack_endp, &errval, - &errstring)) + if (_dl_map_object_1 (l, &fd, fbp, mode, loader, stack_endp, &errval, + &errstring, do_mmap)) goto lose; _dl_process_phdrs (l, fd); diff --git a/elf/dl-load.h b/elf/dl-load.h index ecf6910c68..eff5146acd 100644 --- a/elf/dl-load.h +++ b/elf/dl-load.h @@ -80,6 +80,9 @@ struct loadcmd int prot; /* PROT_* bits. */ }; +static void * +do_mmap (void *addr, size_t length, int prot, int flags, + void *arg, off_t offset); /* This is a subroutine of _dl_map_segments. It should be called for each load command, some time after L->l_addr has been set correctly. It is @@ -113,13 +116,14 @@ _dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header, The file defines this function. The canonical implementation in elf/dl-map-segments.h might be replaced by a sysdeps version. */ -static const char *_dl_map_segments (struct link_map *l, int fd, +static const char *_dl_map_segments (struct link_map *l, void *fd, const ElfW(Ehdr) *header, int type, const struct loadcmd loadcmds[], size_t nloadcmds, const size_t maplength, bool has_holes, - struct link_map *loader); + struct link_map *loader, + __typeof (do_mmap) *m_map); /* All the error message strings _dl_map_segments might return are listed here so that different implementations in different sysdeps diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h index ed7675cabf..7bcfcd9eff 100644 --- a/elf/dl-map-segments.h +++ b/elf/dl-map-segments.h @@ -74,11 +74,11 @@ _dl_map_segment (ElfW(Addr) mappref, size_t maplength, size_t mapalign) other use of those parts of the address space). */ static __always_inline const char * -_dl_map_segments (struct link_map *l, int fd, +_dl_map_segments (struct link_map *l, void *fd, const ElfW(Ehdr) *header, int type, const struct loadcmd loadcmds[], size_t nloadcmds, const size_t maplength, bool has_holes, - struct link_map *loader) + struct link_map *loader, __typeof (do_mmap) *m_map) { const struct loadcmd *c = loadcmds; @@ -138,7 +138,7 @@ _dl_map_segments (struct link_map *l, int fd, { if (c->mapend > c->mapstart /* Map the segment contents from the file. */ - && (__mmap ((void *) (l->l_addr + c->mapstart), + && (m_map ((void *) (l->l_addr + c->mapstart), c->mapend - c->mapstart, c->prot, MAP_FIXED|MAP_COPY|MAP_FILE, fd, c->mapoff) From patchwork Mon Apr 3 09:04:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 67205 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 71CEE385022E for ; Mon, 3 Apr 2023 09:08:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 71CEE385022E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680512904; bh=69GoGOP2QSndQhslMa9NtNYK3RDb16d4wNtb5SHrJpk=; 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=fqImYZtsSbtHj17EHcSGnzIwyS5UmP4gWTfuLxBSvIBmrCKmQDMqfxrJJnIS7IGjg mJWrNFbCQzQBmfRKGHpKvWAsitay9JHo0nxWT6MKzu7sDDJavnUn5isJLoIgnpBPUx Id0cRzxWldo2PFh7+x8b63gWYRICB4sLELaCZiZQ= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from forward203c.mail.yandex.net (forward203c.mail.yandex.net [IPv6:2a02:6b8:c03:500:1:45:d181:d203]) by sourceware.org (Postfix) with ESMTPS id E264B38432DE for ; Mon, 3 Apr 2023 09:04:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E264B38432DE 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 forward203c.mail.yandex.net (Yandex) with ESMTP id 5D688600DD for ; Mon, 3 Apr 2023 12:04:54 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id h4J5UKjDcmI0-dZzThYJZ; Mon, 03 Apr 2023 12:04:53 +0300 X-Yandex-Fwd: 1 To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 08/12] elf: call _dl_map_segment() via premap callback Date: Mon, 3 Apr 2023 14:04:17 +0500 Message-Id: <20230403090421.560208-9-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+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" This allows to install custom premap callbacks in the subsequent patches. The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev --- elf/dl-load.c | 13 ++++++++++--- elf/dl-load.h | 6 +++++- elf/dl-map-segments.h | 7 +++++-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index c0704dc89c..59be8080dd 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -980,7 +980,8 @@ _dl_map_object_1 (struct link_map *l, void *fd, int mode, struct link_map *loader, void **stack_endp, int *errval_p, const char **errstring_p, - __typeof (do_mmap) *m_map) + __typeof (do_mmap) *m_map, + dl_premap_t *premap) { const ElfW(Ehdr) *header; const ElfW(Phdr) *phdr; @@ -1180,7 +1181,7 @@ _dl_map_object_1 (struct link_map *l, void *fd, l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr */ errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds, - maplength, has_holes, loader, m_map); + maplength, has_holes, loader, m_map, premap); if (__glibc_unlikely (errstring != NULL)) { /* Mappings can be in an inconsistent state: avoid unmap. */ @@ -1439,6 +1440,12 @@ do_mmap (void *addr, size_t length, int prot, int flags, return __mmap (addr, length, prot, flags, fd, offset); } +static void * +do_map_segment (void *mappref, size_t maplength, size_t mapalign, void *cookie) +{ + return (void *) _dl_map_segment ((ElfW(Addr)) mappref, maplength, mapalign); +} + #ifndef EXTERNAL_MAP_FROM_FD static #endif @@ -1560,7 +1567,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, } if (_dl_map_object_1 (l, &fd, fbp, mode, loader, stack_endp, &errval, - &errstring, do_mmap)) + &errstring, do_mmap, do_map_segment)) goto lose; _dl_process_phdrs (l, fd); diff --git a/elf/dl-load.h b/elf/dl-load.h index eff5146acd..e777da5838 100644 --- a/elf/dl-load.h +++ b/elf/dl-load.h @@ -84,6 +84,9 @@ static void * do_mmap (void *addr, size_t length, int prot, int flags, void *arg, off_t offset); +typedef void * +(dl_premap_t) (void *mappref, size_t maplength, size_t mapalign, void *cookie); + /* This is a subroutine of _dl_map_segments. It should be called for each load command, some time after L->l_addr has been set correctly. It is responsible for setting up the l_text_end and l_phdr fields. */ @@ -123,7 +126,8 @@ static const char *_dl_map_segments (struct link_map *l, void *fd, const size_t maplength, bool has_holes, struct link_map *loader, - __typeof (do_mmap) *m_map); + __typeof (do_mmap) *m_map, + dl_premap_t *premap); /* All the error message strings _dl_map_segments might return are listed here so that different implementations in different sysdeps diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h index 7bcfcd9eff..7e3c3b6d53 100644 --- a/elf/dl-map-segments.h +++ b/elf/dl-map-segments.h @@ -78,7 +78,8 @@ _dl_map_segments (struct link_map *l, void *fd, const ElfW(Ehdr) *header, int type, const struct loadcmd loadcmds[], size_t nloadcmds, const size_t maplength, bool has_holes, - struct link_map *loader, __typeof (do_mmap) *m_map) + struct link_map *loader, __typeof (do_mmap) *m_map, + dl_premap_t *premap) { const struct loadcmd *c = loadcmds; @@ -100,7 +101,9 @@ _dl_map_segments (struct link_map *l, void *fd, - MAP_BASE_ADDR (l)); /* Remember which part of the address space this object uses. */ - l->l_map_start = _dl_map_segment (mappref, maplength, c->mapalign); + l->l_map_start = (ElfW(Addr)) premap ((void *) mappref, + maplength, c->mapalign, + fd); if (__glibc_unlikely ((void *) l->l_map_start == MAP_FAILED)) return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; From patchwork Mon Apr 3 09:04:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 67202 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 658F23881D01 for ; Mon, 3 Apr 2023 09:07:37 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 658F23881D01 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680512857; bh=E1zxOPymMAC4LBvd6qzn72eHqJGplJKL962wGrMT0UQ=; 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=ekBYfhXou+maSyTb1tADKGDa+adif5uMLapOljQCGwWPh4x2w3Wii7DvMpCW2HRcr oko6CdwI7AM7CdWcybieyVZwW/gNCutQcXQoeN0sP8oTtqjEmUHAVd2/N845JBbmjD bYZU8mkkXtHzo0aYM2hGKaNb6ytcJKI5VQQ0x9Qk= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from forward205c.mail.yandex.net (forward205c.mail.yandex.net [IPv6:2a02:6b8:c03:500:1:45:d181:d205]) by sourceware.org (Postfix) with ESMTPS id 8566A3858023 for ; Mon, 3 Apr 2023 09:04:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8566A3858023 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 forward205c.mail.yandex.net (Yandex) with ESMTP id 6CF4C46CF4 for ; Mon, 3 Apr 2023 12:04:55 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id h4J5UKjDcmI0-mFFRN7Te; Mon, 03 Apr 2023 12:04:54 +0300 X-Yandex-Fwd: 1 To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 09/12] elf: convert _dl_map_object to a callback Date: Mon, 3 Apr 2023 14:04:18 +0500 Message-Id: <20230403090421.560208-10-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.1 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+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" Subsequent patches will add _dl_map_object_from_memory(). The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev --- elf/dl-load.c | 12 ++++++++++-- elf/dl-main.h | 9 +++++++++ elf/dl-open.c | 25 +++++++++++++++++++++---- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index 59be8080dd..6708210da7 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -2331,8 +2331,8 @@ ___dl_map_object (struct link_map *loader, const char *name, } struct link_map * -_dl_map_object (struct link_map *loader, const char *name, - int type, int trace_mode, +__dl_map_object (struct link_map *loader, const char *name, + void *private, int type, int trace_mode, int mode, Lmid_t nsid) { struct link_map *ret; @@ -2343,6 +2343,14 @@ _dl_map_object (struct link_map *loader, const char *name, return ret; } +struct link_map * +_dl_map_object (struct link_map *loader, const char *name, + int type, int trace_mode, + int mode, Lmid_t nsid) +{ + return __dl_map_object (loader, name, NULL, type, trace_mode, mode, nsid); +} + struct add_path_state { bool counting; diff --git a/elf/dl-main.h b/elf/dl-main.h index 92766d06b4..344a87d5e8 100644 --- a/elf/dl-main.h +++ b/elf/dl-main.h @@ -104,6 +104,15 @@ struct dl_main_state bool version_info; }; +/* Open the shared object NAME and map in its segments. + LOADER's DT_RPATH is used in searching for NAME. + If the object is already opened, returns its existing map. */ +extern struct link_map * +__dl_map_object (struct link_map *loader, + const char *name, void *private, + int type, int trace_mode, int mode, + Lmid_t nsid) attribute_hidden; + /* Helper function to invoke _dl_init_paths with the right arguments from *STATE. */ static inline void diff --git a/elf/dl-open.c b/elf/dl-open.c index 2d985e21d8..9055b95f17 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -40,6 +40,7 @@ #include #include +#include /* We must be careful not to leave us in an inconsistent state. Thus we @@ -48,6 +49,7 @@ struct dl_open_args { const char *file; + void *private; int mode; /* This is the caller of the dlopen() function. */ const void *caller_dlopen; @@ -55,6 +57,10 @@ struct dl_open_args /* Namespace ID. */ Lmid_t nsid; + struct link_map * + (*dl_map) (struct link_map *loader, const char *name, void *private, + int type, int trace_mode, int mode, Lmid_t nsid); + /* Original value of _ns_global_scope_pending_adds. Set by dl_open_worker. Only valid if nsid is a real namespace (non-negative). */ @@ -531,7 +537,7 @@ dl_open_worker_begin (void *a) /* Load the named object. */ struct link_map *new; - args->map = new = _dl_map_object (call_map, file, lt_loaded, 0, + args->map = new = args->dl_map (call_map, file, args->private, lt_loaded, 0, mode | __RTLD_CALLMAP, args->nsid); /* If the pointer returned is NULL this means the RTLD_NOLOAD flag is @@ -820,9 +826,11 @@ dl_open_worker (void *a) new->l_name, new->l_ns, new->l_direct_opencount); } -void * -_dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid, - int argc, char *argv[], char *env[]) +static void * +do_dl_open (const char *file, void *private, int mode, + const void *caller_dlopen, Lmid_t nsid, + int argc, char *argv[], char *env[], + __typeof (__dl_map_object) *dl_map) { if ((mode & RTLD_BINDING_MASK) == 0) /* One of the flags must be set. */ @@ -872,10 +880,12 @@ no more namespaces available for dlmopen()")); struct dl_open_args args; args.file = file; + args.private = private; args.mode = mode; args.caller_dlopen = caller_dlopen; args.map = NULL; args.nsid = nsid; + args.dl_map = dl_map; /* args.libc_already_loaded is always assigned by dl_open_worker (before any explicit/non-local returns). */ args.argc = argc; @@ -939,6 +949,13 @@ no more namespaces available for dlmopen()")); return args.map; } +void * +_dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid, + int argc, char *argv[], char *env[]) +{ + return do_dl_open (file, NULL, mode, caller_dlopen, nsid, argc, argv, env, + __dl_map_object); +} void _dl_show_scope (struct link_map *l, int from) From patchwork Mon Apr 3 09:04:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 67206 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 18A0C385020B for ; Mon, 3 Apr 2023 09:09:20 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 18A0C385020B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680512960; bh=rgQYLYwjHB5IZXFM1ynK8HELPPnx6JH77DnXqSsTMRo=; 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=th7LDMeyYoDOZfV6ui8mSoxlCc1+NbW+lMMiT8JG41tz2XeZct7W5OBfhIj2mpw2K 189kEwADoKTac8MHkZB37OoXnI34Q53uBQ00rqa9OqpldFRlHDK7BYFeg9YB0/uDpc nw+qtYArOdDLzWwla+tuJXMZic1+WR4qYacOJ/+4= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from forward200b.mail.yandex.net (forward200b.mail.yandex.net [178.154.239.157]) by sourceware.org (Postfix) with ESMTPS id CC9623858434 for ; Mon, 3 Apr 2023 09:04:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CC9623858434 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 forward200b.mail.yandex.net (Yandex) with ESMTP id 659596011A for ; Mon, 3 Apr 2023 12:04:57 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id h4J5UKjDcmI0-sCPuL9UT; Mon, 03 Apr 2023 12:04:56 +0300 X-Yandex-Fwd: 1 To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 10/12] dlfcn,elf: implement dlmem() [BZ #11767] Date: Mon, 3 Apr 2023 14:04:19 +0500 Message-Id: <20230403090421.560208-11-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.3 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, 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+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" This patch adds the following function: void *dlmem(const unsigned char *buffer, size_t size, int flags, struct dlmem_args *dlm_args); It is the same as dlopen() but allows to dynamic-link solibs from the memory buffer, rather than from a file as dlopen() does. "buffer" arg is the pointer to the solib image in memory. "size" is the solib image size. Must be smaller-or-equal to the actual buffer size. "flags" is the same flags argument used in dlopen(). "dlm_args" is an optional argument that allows to specify the load namespace and a premap callback. This implementation is trying a "zero-copy" technique first, but it works only with linux kernels 5.13 and newer. So the memcpy() fall-back is added as well. This patch adds a test-case named tst-dlmem-fdlopen. It implements a bsd-compatible fdlopen() on top of dlmem() and loads a test lib with it. It then checks /proc//maps to make sure the library was mmap()ed rather then memcopied. Then it does the regular set of solib tests. The test-suite was run on x86_64/64 and showed no regressions. Signed-off-by: Stas Sergeev --- dlfcn/Makefile | 10 +- dlfcn/Versions | 3 + dlfcn/dlfcn.h | 22 +++ dlfcn/dlmem.c | 86 +++++++++ dlfcn/tst-dlmem-extfns.c | 175 ++++++++++++++++++ elf/dl-load.c | 173 +++++++++++++++++ elf/dl-load.h | 3 + elf/dl-main.h | 12 ++ elf/dl-object.c | 5 +- elf/dl-open.c | 13 ++ elf/rtld.c | 1 + manual/dynlink.texi | 1 + sysdeps/generic/ldsodefs.h | 9 + sysdeps/mach/hurd/i386/libc.abilist | 1 + sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 + sysdeps/unix/sysv/linux/arc/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/le/libc.abilist | 1 + sysdeps/unix/sysv/linux/csky/libc.abilist | 1 + sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 + sysdeps/unix/sysv/linux/i386/libc.abilist | 1 + sysdeps/unix/sysv/linux/ia64/libc.abilist | 1 + .../sysv/linux/loongarch/lp64/libc.abilist | 1 + .../sysv/linux/m68k/coldfire/libc.abilist | 1 + .../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 + .../sysv/linux/microblaze/be/libc.abilist | 1 + .../sysv/linux/microblaze/le/libc.abilist | 1 + .../sysv/linux/mips/mips32/fpu/libc.abilist | 1 + .../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 + .../sysv/linux/mips/mips64/n32/libc.abilist | 1 + .../sysv/linux/mips/mips64/n64/libc.abilist | 1 + sysdeps/unix/sysv/linux/nios2/libc.abilist | 1 + sysdeps/unix/sysv/linux/or1k/libc.abilist | 1 + .../linux/powerpc/powerpc32/fpu/libc.abilist | 1 + .../powerpc/powerpc32/nofpu/libc.abilist | 1 + .../linux/powerpc/powerpc64/be/libc.abilist | 1 + .../linux/powerpc/powerpc64/le/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv32/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv64/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-32/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-64/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/le/libc.abilist | 1 + .../sysv/linux/sparc/sparc32/libc.abilist | 1 + .../sysv/linux/sparc/sparc64/libc.abilist | 1 + .../unix/sysv/linux/x86_64/64/libc.abilist | 1 + .../unix/sysv/linux/x86_64/x32/libc.abilist | 1 + 48 files changed, 546 insertions(+), 2 deletions(-) create mode 100644 dlfcn/dlmem.c create mode 100644 dlfcn/tst-dlmem-extfns.c diff --git a/dlfcn/Makefile b/dlfcn/Makefile index 1fa7fea1ef..55e5f5fcdf 100644 --- a/dlfcn/Makefile +++ b/dlfcn/Makefile @@ -28,6 +28,7 @@ routines = \ dlclose \ dlerror \ dlinfo \ + dlmem \ dlmopen \ dlopen \ dlsym \ @@ -51,7 +52,8 @@ 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 + bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen tst-dlmem-extfns +CPPFLAGS-tst-dlmem-extfns.c += -DBUILDDIR=\"$(objpfx)\" endif modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \ defaultmod2 errmsg1mod modatexit modcxaatexit \ @@ -102,6 +104,12 @@ $(objpfx)glrefmain.out: $(objpfx)glrefmain \ $(objpfx)failtest.out: $(objpfx)failtestmod.so $(objpfx)tst-dladdr.out: $(objpfx)glreflib1.so +# Create fancy container file with solib within. +$(objpfx)glreflib1.img: $(objpfx)glreflib1.so + dd if=/dev/urandom bs=512 count=1 >$@ + cat $^ >>$@ + dd if=/dev/urandom bs=512 count=1 >>$@ +$(objpfx)tst-dlmem-extfns.out: $(objpfx)glreflib1.so $(objpfx)glreflib1.img $(objpfx)tst-dlinfo.out: $(objpfx)glreflib3.so LDFLAGS-glreflib3.so = -Wl,-rpath,: diff --git a/dlfcn/Versions b/dlfcn/Versions index cc34eb824d..b427c9c3a3 100644 --- a/dlfcn/Versions +++ b/dlfcn/Versions @@ -28,6 +28,9 @@ libc { dlsym; dlvsym; } + GLIBC_2.38 { + dlmem; + } GLIBC_PRIVATE { __libc_dlerror_result; _dlerror_run; diff --git a/dlfcn/dlfcn.h b/dlfcn/dlfcn.h index c5d192597d..fe5e5a7d09 100644 --- a/dlfcn/dlfcn.h +++ b/dlfcn/dlfcn.h @@ -68,6 +68,28 @@ extern void *dlsym (void *__restrict __handle, /* Like `dlopen', but request object to be allocated in a new namespace. */ extern void *dlmopen (Lmid_t __nsid, const char *__file, int __mode) __THROWNL; +/* Callback for dlmem. */ +typedef void * +(dlmem_premap_t) (void *mappref, size_t maplength, size_t mapalign, + void *cookie); + +struct dlmem_args { + /* Optional name to associate with the loaded object. */ + const char *soname; + /* Namespace where to load the object. */ + Lmid_t nsid; + /* dlmem-specific flags. */ + unsigned int flags; + /* Optional premap callback. */ + dlmem_premap_t *premap; + /* Optional argument for premap callback. */ + void *cookie; +}; + +/* Like `dlmopen', but loads shared object from memory buffer. */ +extern void *dlmem (const unsigned char *buffer, size_t size, int mode, + struct dlmem_args *dlm_args); + /* Find the run-time address in the shared object HANDLE refers to of the symbol called NAME with VERSION. */ extern void *dlvsym (void *__restrict __handle, diff --git a/dlfcn/dlmem.c b/dlfcn/dlmem.c new file mode 100644 index 0000000000..d59eb99ec1 --- /dev/null +++ b/dlfcn/dlmem.c @@ -0,0 +1,86 @@ +/* Load a shared object from memory. + Copyright (C) 1995-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 + +struct _dlmem_args +{ + /* The arguments for dlmem_doit. */ + const unsigned char *buffer; + size_t size; + int mode; + struct dlmem_args *args; + /* The return value of dlmem_doit. */ + void *new; + /* Address of the caller. */ + const void *caller; +}; + +static void +dlmem_doit (void *a) +{ + struct _dlmem_args *args = (struct _dlmem_args *) a; + + 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)) + _dl_signal_error (EINVAL, NULL, NULL, _("buffer not aligned")); + + args->new = GLRO(dl_mem) (args->buffer, args->size, + args->mode | __RTLD_DLOPEN, + args->args, + args->caller, + __libc_argc, __libc_argv, __environ); +} + + +static void * +dlmem_implementation (const unsigned char *buffer, size_t size, int mode, + struct dlmem_args *dlm_args, void *dl_caller) +{ + struct _dlmem_args args; + args.buffer = buffer; + args.size = size; + args.mode = mode; + args.args = dlm_args; + args.caller = dl_caller; + + return _dlerror_run (dlmem_doit, &args) ? NULL : args.new; +} + +void * +___dlmem (const unsigned char *buffer, size_t size, int mode, + struct dlmem_args *dlm_args) +{ + return dlmem_implementation (buffer, size, mode, dlm_args, + RETURN_ADDRESS (0)); +} + +#ifdef SHARED +versioned_symbol (libc, ___dlmem, dlmem, GLIBC_2_38); +#else /* !SHARED */ +weak_alias (___dlmem, dlmem) +static_link_warning (dlmem) +#endif /* !SHARED */ diff --git a/dlfcn/tst-dlmem-extfns.c b/dlfcn/tst-dlmem-extfns.c new file mode 100644 index 0000000000..3b98a6e859 --- /dev/null +++ b/dlfcn/tst-dlmem-extfns.c @@ -0,0 +1,175 @@ +/* Test for external functions (fdlopen, dlopen_with_offset4) on top of dlmem. + 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 +#include + +/* Load the shared library from an open fd. */ +static void * +fdlopen (int fd, int flags) +{ + off_t len; + void *addr; + void *handle; + + 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) + return NULL; + handle = dlmem (addr, len, flags, NULL); + munmap (addr, len); + return handle; +} + +/* Load the shared library from a container file. + file - file name. + offset - solib offset within a container file. + Highly recommended to be page-aligned. + length - solib file length (not a container file length). + flags - dlopen() flags. */ +void *dlopen_with_offset4 (const char *file, off_t offset, size_t length, + int flags) +{ + void *addr; + void *handle; + int fd; + off_t pad_size = (offset & (getpagesize () - 1)); + off_t aligned_offset = offset - pad_size; + size_t map_length = length + pad_size; + + fd = open (file, O_RDONLY); + if (fd == -1) + return NULL; + addr = mmap (NULL, map_length, PROT_READ, MAP_PRIVATE, fd, aligned_offset); + close(fd); + if (addr == MAP_FAILED) + return NULL; + if (pad_size) + { + /* We need to fix alignment by hands. :-( + And for that we need a shared mapping. */ + void *addr2 = mmap (NULL, length, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (addr2 == MAP_FAILED) + { + munmap (addr, map_length); + return NULL; + } + memcpy (addr2, addr + pad_size, length); + munmap (addr, map_length); + addr = addr2; + map_length = length; + } + handle = dlmem (addr, length, flags, NULL); + munmap (addr, map_length); + return handle; +} + + +#define TEST_FUNCTION do_test +extern int do_test (void); + +int +do_test (void) +{ + char cmd[256]; + void *handle; + int (*sym) (void); /* We load ref1 from glreflib1.c. */ + Dl_info info; + int rc; + int fd; + struct stat sb; + const unsigned char *unaligned_buf = (const unsigned char *) 1; + + /* First check the reaction to unaligned buf. */ + handle = dlmem (unaligned_buf, 4096, RTLD_NOW, 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); + + fd = open (BUILDDIR "glreflib1.so", O_RDONLY); + if (fd == -1) + error (EXIT_FAILURE, 0, "cannot open: glreflib1.so"); + fstat (fd, &sb); + handle = fdlopen (fd, RTLD_NOW); + close (fd); + if (handle == NULL) + { + printf ("fdlopen failed, %s\n", dlerror ()); + exit (EXIT_FAILURE); + } + + /* Check that the lib is properly mmap()ed, rather than memcpy()ed. + This may fail on linux kernels <5.13. */ + snprintf (cmd, sizeof(cmd), "grep glreflib1.so /proc/%i/maps", getpid()); + rc = system (cmd); + TEST_COMPARE (rc, 0); + + sym = dlsym (handle, "ref1"); + if (sym == NULL) + error (EXIT_FAILURE, 0, "dlsym failed"); + + dlclose (handle); + + /* Try to load the solib from container, with the worst, unaligned case. */ + handle = dlopen_with_offset4 (BUILDDIR "glreflib1.img", 512, sb.st_size, + RTLD_NOW); + + sym = dlsym (handle, "ref1"); + if (sym == NULL) + error (EXIT_FAILURE, 0, "dlsym failed"); + + memset (&info, 0, sizeof (info)); + rc = dladdr (sym, &info); + if (rc == 0) + error (EXIT_FAILURE, 0, "dladdr 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); + + 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"); + + /* Handle can be closed only after checking info, as some info fields + point to memory that is freed by dlclose(). */ + dlclose (handle); + return 0; +} + + +#include diff --git a/elf/dl-load.c b/elf/dl-load.c index 6708210da7..fd81a9103e 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -75,6 +75,7 @@ struct filebuf #include #include #include +#include #include #include @@ -2351,6 +2352,178 @@ _dl_map_object (struct link_map *loader, const char *name, return __dl_map_object (loader, name, NULL, type, trace_mode, mode, nsid); } +static void * +do_memremap (void *addr, size_t length, int prot, int flags, + void *arg, off_t offset) +{ + const struct dlmem_fbuf *fb = arg; + size_t to_copy = 0; + + assert (flags & MAP_FIXED); + if (offset < fb->len) + { + to_copy = length; + if (offset + to_copy > fb->len) + to_copy = fb->len - offset; +#ifdef MREMAP_DONTUNMAP + void *addr2 = __mremap ((void *) (fb->buf + offset), to_copy, to_copy, + MREMAP_MAYMOVE | MREMAP_FIXED | MREMAP_DONTUNMAP, + addr); + /* MREMAP_DONTUNMAP introduced in linux-5.7, but only works for + file-based maps since commit a460938 went in 5.13. + So have a fall-back. */ + if (addr2 == MAP_FAILED) + memcpy (addr, fb->buf + offset, to_copy); +#else + /* MREMAP_DONTUNMAP is not always available. This is a fall-back. */ + memcpy (addr, fb->buf + offset, to_copy); +#endif + } + /* memset the rest. */ + if (length > to_copy) + memset (addr + to_copy, 0, length - 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) +{ + struct dlmem_fbuf *fb = cookie; + void *ret = MAP_FAILED; + + if (fb->dlm_args && fb->dlm_args->premap) + ret = fb->dlm_args->premap (mappref, maplength, mapalign, + fb->dlm_args->cookie); + if (ret == MAP_FAILED) + ret = (void *) _dl_map_segment ((ElfW(Addr)) mappref, maplength, + mapalign); + return ret; +} + +static ssize_t +do_pread_memcpy (void *arg, void *buf, size_t count, off_t offset) +{ + struct dlmem_fbuf *fb = arg; + if (offset >= fb->len) + return -1; + if (offset + count > fb->len) + count = fb->len - offset; + if (count) + memcpy (buf, fb->buf + offset, count); + return count; +} + +static struct link_map * +___dl_map_object_from_mem (struct link_map *loader, const char *name, + void *private, int type, int trace_mode, + int mode, Lmid_t nsid, struct filebuf *fbp) +{ + struct link_map *l; + int err; + char *realname; + /* Initialize to keep the compiler happy. */ + const char *errstring = NULL; + int errval = 0; + struct r_debug *r = _dl_debug_update (nsid); + bool make_consistent = false; + struct r_file_id id = {}; + + assert (nsid >= 0); + assert (nsid < GL(dl_nns)); + + if (name && *name) + { + /* Look for this name among those already loaded. */ + l = _dl_check_loaded (name, nsid); + if (l) + return l; + } + + /* Will be true if we found a DSO which is of the other ELF class. */ + bool found_other_class = false; + + err = do_open_verify (name, private, fbp, + loader ?: GL(dl_ns)[nsid]._ns_loaded, + &found_other_class, false, do_pread_memcpy); + if (err) + return NULL; + + /* In case the LOADER information has only been provided to get to + the appropriate RUNPATH/RPATH information we do not need it + anymore. */ + if (mode & __RTLD_CALLMAP) + loader = NULL; + + if (mode & RTLD_NOLOAD) + { + /* We are not supposed to load the object unless it is already + loaded. So return now. */ + return NULL; + } + + /* Print debugging message. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) + _dl_debug_printf ("dlmem [%lu]; generating link map\n", nsid); + + /* _dl_new_object() treats "" separately and doesn't free it. */ + realname = *name ? __strdup (name) : (char *) ""; + /* Enter the new object in the list of loaded objects. */ + l = _dl_new_object (realname, name, type, loader, mode, nsid); + if (__glibc_unlikely (l == NULL)) + { + errstring = N_("cannot create shared object descriptor"); + goto lose_errno; + } + + void *stack_end = __libc_stack_end; + if (_dl_map_object_1 (l, private, fbp, mode, loader, &stack_end, &errval, + &errstring, do_memremap, do_dlmem_premap)) + goto lose; + + _dl_map_object_2 (l, mode, id, NULL, nsid); + return l; + +lose_errno: + errval = errno; +lose: + if (l != NULL && l->l_map_start != 0) + _dl_unmap_segments (l); + if (l != NULL && l->l_origin != (char *) -1l) + free ((char *) l->l_origin); + if (l != NULL && !l->l_libname->dont_free) + free (l->l_libname); + if (l != NULL && l->l_phdr_allocated) + free ((void *) l->l_phdr); + free (l); + + if (make_consistent && r != NULL) + { + r->r_state = RT_CONSISTENT; + _dl_debug_state (); + LIBC_PROBE (map_failed, 2, nsid, r); + } + + _dl_signal_error (errval, NULL, NULL, errstring); + return NULL; +} + +struct link_map * +__dl_map_object_from_mem (struct link_map *loader, const char *name, + void *private, int type, int trace_mode, + int mode, Lmid_t nsid) +{ + struct link_map *ret; + struct filebuf fb = {}; + + ret = ___dl_map_object_from_mem (loader, name, private, type, trace_mode, + mode, nsid, &fb); + filebuf_done (&fb); + return ret; +} + struct add_path_state { bool counting; diff --git a/elf/dl-load.h b/elf/dl-load.h index e777da5838..09b2878260 100644 --- a/elf/dl-load.h +++ b/elf/dl-load.h @@ -106,6 +106,9 @@ _dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header, - c->mapoff); } +static void * +do_mmap (void *addr, size_t length, int prot, int flags, + void *arg, off_t offset); /* This is a subroutine of _dl_map_object_from_fd. It is responsible for filling in several fields in *L: l_map_start, l_map_end, l_addr, diff --git a/elf/dl-main.h b/elf/dl-main.h index 344a87d5e8..e60fafaeb6 100644 --- a/elf/dl-main.h +++ b/elf/dl-main.h @@ -104,6 +104,13 @@ struct dl_main_state bool version_info; }; +struct dlmem_fbuf +{ + ssize_t len; + const unsigned char *buf; + struct dlmem_args *dlm_args; +}; + /* Open the shared object NAME and map in its segments. LOADER's DT_RPATH is used in searching for NAME. If the object is already opened, returns its existing map. */ @@ -112,6 +119,11 @@ __dl_map_object (struct link_map *loader, const char *name, void *private, int type, int trace_mode, int mode, Lmid_t nsid) attribute_hidden; +extern struct link_map * +__dl_map_object_from_mem (struct link_map *loader, + const char *name, void *private, + int type, int trace_mode, int mode, + Lmid_t nsid) attribute_hidden; /* Helper function to invoke _dl_init_paths with the right arguments from *STATE. */ diff --git a/elf/dl-object.c b/elf/dl-object.c index f1f2ec956c..ab926cd4bf 100644 --- a/elf/dl-object.c +++ b/elf/dl-object.c @@ -122,7 +122,10 @@ _dl_new_object (char *realname, const char *libname, int type, #endif new->l_name = realname; else - new->l_name = (char *) newname->name + libname_len - 1; + /* When realname="", it is not allocated and points to the constant + string. Constness is dropped by an explicit cast. :( + So strdup() it here. */ + new->l_name = __strdup (""); new->l_type = type; /* If we set the bit now since we know it is never used we avoid diff --git a/elf/dl-open.c b/elf/dl-open.c index 9055b95f17..bcae45d714 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -957,6 +957,19 @@ _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid, __dl_map_object); } +void * +_dl_mem (const unsigned char *buffer, size_t size, int mode, + struct dlmem_args *dlm_args, const void *caller_dlopen, + int argc, char *argv[], char *env[]) +{ + struct dlmem_fbuf fb = { .buf = buffer, .len = size, .dlm_args = dlm_args }; + Lmid_t nsid = dlm_args ? dlm_args->nsid : LM_ID_BASE; + const char *file = (dlm_args && dlm_args->soname) ? dlm_args->soname : ""; + + return do_dl_open (file, &fb, mode, caller_dlopen, nsid, argc, argv, env, + __dl_map_object_from_mem); +} + void _dl_show_scope (struct link_map *l, int from) { diff --git a/elf/rtld.c b/elf/rtld.c index c1e383b055..30c3190593 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -367,6 +367,7 @@ struct rtld_global_ro _rtld_global_ro attribute_relro = ._dl_mcount = _dl_mcount, ._dl_lookup_symbol_x = _dl_lookup_symbol_x, ._dl_open = _dl_open, + ._dl_mem = _dl_mem, ._dl_close = _dl_close, ._dl_catch_error = _dl_catch_error, ._dl_error_free = _dl_error_free, diff --git a/manual/dynlink.texi b/manual/dynlink.texi index 6a4a50d3f0..21bc6c067c 100644 --- a/manual/dynlink.texi +++ b/manual/dynlink.texi @@ -209,6 +209,7 @@ This function is a GNU extension. @c dladdr1 @c dlclose @c dlerror +@c dlmem @c dlmopen @c dlopen @c dlsym diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index e1ab272a79..fae485fe1f 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -664,6 +664,9 @@ struct rtld_global_ro struct link_map *); void *(*_dl_open) (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid, int argc, char *argv[], char *env[]); + void *(*_dl_mem) (const unsigned char *buffer, size_t size, int mode, + struct dlmem_args *dlm_args, const void *caller_dlopen, + int argc, char *argv[], char *env[]); void (*_dl_close) (void *map); /* libdl in a secondary namespace (after dlopen) must use _dl_catch_error from the main namespace, so it has to be @@ -1235,6 +1238,12 @@ extern void *_dl_open (const char *name, int mode, const void *caller, Lmid_t nsid, int argc, char *argv[], char *env[]) attribute_hidden; +/* Open shared object from memory buffer. */ +extern void *_dl_mem (const unsigned char *buffer, size_t size, int mode, + struct dlmem_args *dlm_args, const void *caller, + int argc, char *argv[], char *env[]) + attribute_hidden; + /* Free or queue for freeing scope OLD. If other threads might be in the middle of _dl_fixup, _dl_profile_fixup or dl*sym using the old scope, OLD can't be freed until no thread is using it. */ diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist index ed0c4789eb..1880004336 100644 --- a/sysdeps/mach/hurd/i386/libc.abilist +++ b/sysdeps/mach/hurd/i386/libc.abilist @@ -2326,6 +2326,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 __confstr_chk F GLIBC_2.4 __fgets_chk F GLIBC_2.4 __fgets_unlocked_chk F diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index 0e2d9c3045..c4d31cabed 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2665,3 +2665,4 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index f1bec1978d..93b37a1e1d 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -2774,6 +2774,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 _IO_fprintf F GLIBC_2.4 _IO_printf F GLIBC_2.4 _IO_sprintf F diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist index aa874b88d0..9fec2308c3 100644 --- a/sysdeps/unix/sysv/linux/arc/libc.abilist +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist @@ -2426,3 +2426,4 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist index afbd57da6f..bd0f04e58a 100644 --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist @@ -546,6 +546,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 _Exit F GLIBC_2.4 _IO_2_1_stderr_ D 0xa0 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0 diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist index e7364cd3fe..dccc49c8d6 100644 --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist @@ -543,6 +543,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 _Exit F GLIBC_2.4 _IO_2_1_stderr_ D 0xa0 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0 diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist index 913fa59215..0df8524ac0 100644 --- a/sysdeps/unix/sysv/linux/csky/libc.abilist +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist @@ -2702,3 +2702,4 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index 43af3a9811..fa4680e97a 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -2651,6 +2651,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 __confstr_chk F GLIBC_2.4 __fgets_chk F GLIBC_2.4 __fgets_unlocked_chk F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index af72f8fab0..bfb1bde49d 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -2835,6 +2835,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 __confstr_chk F GLIBC_2.4 __fgets_chk F GLIBC_2.4 __fgets_unlocked_chk F diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist index 48cbb0fa50..e53505abe0 100644 --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist @@ -2600,6 +2600,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 __confstr_chk F GLIBC_2.4 __fgets_chk F GLIBC_2.4 __fgets_unlocked_chk F diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist index c15884bb0b..9f56cbdcab 100644 --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist @@ -2186,3 +2186,4 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index 3738db81df..d5443b1198 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -547,6 +547,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 _Exit F GLIBC_2.4 _IO_2_1_stderr_ D 0x98 GLIBC_2.4 _IO_2_1_stdin_ D 0x98 diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index ed13627752..640c8b8c4a 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2778,6 +2778,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 __confstr_chk F GLIBC_2.4 __fgets_chk F GLIBC_2.4 __fgets_unlocked_chk F diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist index 8357738621..79b400efc6 100644 --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist @@ -2751,3 +2751,4 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist index 58c5da583d..38b4098950 100644 --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist @@ -2748,3 +2748,4 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index d3741945cd..9a4f909a25 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -2743,6 +2743,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 __confstr_chk F GLIBC_2.4 __fgets_chk F GLIBC_2.4 __fgets_unlocked_chk F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist index 5319fdc204..c8b9f85fdb 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -2741,6 +2741,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 __confstr_chk F GLIBC_2.4 __fgets_chk F GLIBC_2.4 __fgets_unlocked_chk F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index 1743ea6eb9..0887b67394 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -2749,6 +2749,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 __confstr_chk F GLIBC_2.4 __fgets_chk F GLIBC_2.4 __fgets_unlocked_chk F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index 9b1f53c6ac..1c3a6f4bee 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -2651,6 +2651,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 __confstr_chk F GLIBC_2.4 __fgets_chk F GLIBC_2.4 __fgets_unlocked_chk F diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist index ae1c6ca1b5..31b23859a4 100644 --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist @@ -2790,3 +2790,4 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist index a7c572c947..59f4aa7766 100644 --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist @@ -2172,3 +2172,4 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index 074fa031a7..d715d0ae97 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -2817,6 +2817,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 _IO_fprintf F GLIBC_2.4 _IO_printf F GLIBC_2.4 _IO_sprintf F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist index dfcb4bd2d5..3addcf3d17 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -2850,6 +2850,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 _IO_fprintf F GLIBC_2.4 _IO_printf F GLIBC_2.4 _IO_sprintf F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist index 63bbccf3f9..5365978277 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist @@ -2571,6 +2571,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 _IO_fprintf F GLIBC_2.4 _IO_printf F GLIBC_2.4 _IO_sprintf F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist index ab85fd61ef..f0af576192 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist @@ -2885,3 +2885,4 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F +GLIBC_2.38 dlmem F diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist index b716f5c763..941fd40ea8 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist @@ -2428,3 +2428,4 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist index 774e777b65..74f58439ad 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2628,3 +2628,4 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index 8625135c48..cf3a10aa76 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -2815,6 +2815,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 _IO_fprintf F GLIBC_2.4 _IO_printf F GLIBC_2.4 _IO_sprintf F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index d00c7eb262..2ad97f87b2 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -2608,6 +2608,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 _IO_fprintf F GLIBC_2.4 _IO_printf F GLIBC_2.4 _IO_sprintf F diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist index b63037241d..7c81b94953 100644 --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist @@ -2658,6 +2658,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 __confstr_chk F GLIBC_2.4 __fgets_chk F GLIBC_2.4 __fgets_unlocked_chk F diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist index d80055617d..0493d6b456 100644 --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist @@ -2655,6 +2655,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 __confstr_chk F GLIBC_2.4 __fgets_chk F GLIBC_2.4 __fgets_unlocked_chk F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index 5be55c11d2..6fd09f6499 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -2810,6 +2810,7 @@ GLIBC_2.38 __nldbl___isoc23_vsscanf F GLIBC_2.38 __nldbl___isoc23_vswscanf F GLIBC_2.38 __nldbl___isoc23_vwscanf F GLIBC_2.38 __nldbl___isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 _IO_fprintf F GLIBC_2.4 _IO_printf F GLIBC_2.4 _IO_sprintf F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index 475fdaae15..24dbc4801f 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2623,6 +2623,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 __confstr_chk F GLIBC_2.4 __fgets_chk F GLIBC_2.4 __fgets_unlocked_chk F diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index 6cfb928bc8..522ca8e8aa 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2574,6 +2574,7 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F GLIBC_2.4 __confstr_chk F GLIBC_2.4 __fgets_chk F GLIBC_2.4 __fgets_unlocked_chk F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index c735097172..42b170c805 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2680,3 +2680,4 @@ GLIBC_2.38 __isoc23_wcstoull F GLIBC_2.38 __isoc23_wcstoull_l F GLIBC_2.38 __isoc23_wcstoumax F GLIBC_2.38 __isoc23_wscanf F +GLIBC_2.38 dlmem F From patchwork Mon Apr 3 09:04:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 67204 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 252D03857007 for ; Mon, 3 Apr 2023 09:08:09 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 252D03857007 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680512889; bh=2T38M7MdIEu1JaqqWIPHNSGNebBacpmit7RkKbjjdpM=; 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=bPHfjwsNTmwkkMQi4t1fLoaGeBOLn+ERiA8W9HUVgHrsz4WFA97iwPnbAS3UCyKzQ rPMoN62FnGLjorX3G5fK6zszfXaBWnWSpt6tn+IoYSjCGsidqQklFJwMEuyfoEhX8w ijfdPngChE8bkKunLlnc/TCxScnkqja//FgivuPA= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from forward200b.mail.yandex.net (forward200b.mail.yandex.net [178.154.239.157]) by sourceware.org (Postfix) with ESMTPS id 71DF838432CB for ; Mon, 3 Apr 2023 09:04:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 71DF838432CB 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 forward200b.mail.yandex.net (Yandex) with ESMTP id 716A3600E1 for ; Mon, 3 Apr 2023 12:04:58 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-73.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id h4J5UKjDcmI0-wyOukZZ7; Mon, 03 Apr 2023 12:04:57 +0300 X-Yandex-Fwd: 1 To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 11/12] dlfcn,elf: impl DLMEM_DONTREPLACE dlmem() flag Date: Mon, 3 Apr 2023 14:04:20 +0500 Message-Id: <20230403090421.560208-12-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, KAM_SHORT, 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+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" 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 | 4 + dlfcn/glreflib1.c | 2 + dlfcn/tst-dlmem-shm.c | 169 ++++++++++++++++++++++++++++++++++++++++++ elf/dl-load.c | 36 ++++++++- elf/dl-map-segments.h | 4 +- 6 files changed, 216 insertions(+), 4 deletions(-) create mode 100644 dlfcn/tst-dlmem-shm.c diff --git a/dlfcn/Makefile b/dlfcn/Makefile index 55e5f5fcdf..a71810e941 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-extfns + bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen tst-dlmem-extfns \ + tst-dlmem-shm CPPFLAGS-tst-dlmem-extfns.c += -DBUILDDIR=\"$(objpfx)\" +CPPFLAGS-tst-dlmem-shm.c += -DBUILDDIR=\"$(objpfx)\" endif modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \ defaultmod2 errmsg1mod modatexit modcxaatexit \ @@ -110,6 +112,7 @@ $(objpfx)glreflib1.img: $(objpfx)glreflib1.so cat $^ >>$@ dd if=/dev/urandom bs=512 count=1 >>$@ $(objpfx)tst-dlmem-extfns.out: $(objpfx)glreflib1.so $(objpfx)glreflib1.img +$(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 fe5e5a7d09..7aa9d7d3cf 100644 --- a/dlfcn/dlfcn.h +++ b/dlfcn/dlfcn.h @@ -73,6 +73,10 @@ typedef void * (dlmem_premap_t) (void *mappref, size_t maplength, size_t mapalign, void *cookie); +/* Do not replace mapping created by premap callback. + 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 fd81a9103e..422c03459b 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -2352,6 +2352,31 @@ _dl_map_object (struct link_map *loader, const char *name, return __dl_map_object (loader, name, NULL, type, trace_mode, mode, nsid); } +static void * +do_mmapcpy (void *addr, size_t length, int prot, int flags, + void *arg, off_t offset) +{ + const struct dlmem_fbuf *fb = arg; + size_t to_copy = 0; + + assert (flags & MAP_FIXED); + assert ((flags & MAP_ANONYMOUS) || fb); + + if (!(flags & MAP_ANONYMOUS) && offset < fb->len) + { + to_copy = length; + if (offset + to_copy > fb->len) + to_copy = fb->len - offset; + memcpy (addr, fb->buf + offset, to_copy); + } + /* memset the rest. */ + if (length > to_copy) + memset (addr + to_copy, 0, length - to_copy); + if (__mprotect (addr, length, prot) == -1) + return MAP_FAILED; + return addr; +} + static void * do_memremap (void *addr, size_t length, int prot, int flags, void *arg, off_t offset) @@ -2360,6 +2385,11 @@ do_memremap (void *addr, size_t length, int prot, int flags, size_t to_copy = 0; assert (flags & MAP_FIXED); + assert ((flags & MAP_ANONYMOUS) || fb); + + if (flags & MAP_ANONYMOUS) + return __mmap (addr, length, prot, flags, -1, 0); + if (offset < fb->len) { to_copy = length; @@ -2430,6 +2460,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)); @@ -2480,7 +2514,7 @@ ___dl_map_object_from_mem (struct link_map *loader, const char *name, void *stack_end = __libc_stack_end; if (_dl_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; _dl_map_object_2 (l, mode, id, NULL, nsid); diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h index 7e3c3b6d53..3fb9aac6cb 100644 --- a/elf/dl-map-segments.h +++ b/elf/dl-map-segments.h @@ -187,9 +187,9 @@ _dl_map_segments (struct link_map *l, void *fd, { /* Map the remaining zero pages in from the zero fill FD. */ caddr_t mapat; - mapat = __mmap ((caddr_t) zeropage, zeroend - zeropage, + mapat = m_map ((caddr_t) zeropage, zeroend - zeropage, c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED, - -1, 0); + NULL, 0); if (__glibc_unlikely (mapat == MAP_FAILED)) return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL; } 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: 67203 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6D8EF3853D0D for ; Mon, 3 Apr 2023 09:08:02 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6D8EF3853D0D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680512882; 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=WOfmVj8qFW3yS/a1HAG4FJPuIkLw6rP8GyyWuTqzbCEbO8SobOdXKCNLiZTMNfWkw os1Io9TgOzAFTre0t+sjjnWEfOEtyZhXSXPDyygZ2+suXMa2o/Qr9HFRJJPCbU1UO/ 9pLE85b02Ej05hNJYjI5nYO7jwC4JWGRVHrRq/Vk= 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+patchwork=sourceware.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;