From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from forward104o.mail.yandex.net (forward104o.mail.yandex.net [IPv6:2a02:6b8:0:1a2d::607]) by sourceware.org (Postfix) with ESMTPS id 879DF3850232 for ; Sat, 18 Mar 2023 16:51:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 879DF3850232 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=yandex.ru Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=yandex.ru Received: from myt6-1289f562e823.qloud-c.yandex.net (myt6-1289f562e823.qloud-c.yandex.net [IPv6:2a02:6b8:c12:259d:0:640:1289:f562]) by forward104o.mail.yandex.net (Yandex) with ESMTP id 9056F65D44BC for ; Sat, 18 Mar 2023 19:51:47 +0300 (MSK) Received: by myt6-1289f562e823.qloud-c.yandex.net (smtp/Yandex) with ESMTPSA id cpp3fcrbC8c1-EytCdIkb; Sat, 18 Mar 2023 19:51:45 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex.ru; s=mail; t=1679158306; bh=c4/vAJj3Rc2DQVpq2ANx8hvb44Wh+yUDEks2ydpx5Js=; h=Message-Id:Date:In-Reply-To:Cc:Subject:References:To:From; b=ixEwr3NW4oSs/Sv71J9GhkPJrY4fM8YO4LXWAX07NEGQgwbQHB0o7vXF7Y4UqO1q9 7czNLmfu9xwYw5vImqpQFdkTtdUs00wvng7wmTrFgP4U1usRpBawR4/E8PcuArpHZp YmczXOe4sTbuK7f4ZfKjExvD539s1m/JW2iHvmZ8= Authentication-Results: myt6-1289f562e823.qloud-c.yandex.net; dkim=pass header.i=@yandex.ru From: Stas Sergeev To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 04/13] elf: split _dl_map_object_from_fd() into reusable parts Date: Sat, 18 Mar 2023 21:51:01 +0500 Message-Id: <20230318165110.3672749-5-stsp2@yandex.ru> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20230318165110.3672749-1-stsp2@yandex.ru> References: <20230318165110.3672749-1-stsp2@yandex.ru> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.2 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 List-Id: 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 | 317 ++++++++++++++++++++++++++++---------------------- 1 file changed, 175 insertions(+), 142 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index ab8b648687..9e0e63b9a3 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -929,147 +929,25 @@ _dl_process_pt_gnu_property (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. */ - -#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 +_ld_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; - struct r_debug *r = _dl_debug_update (nsid); - bool make_consistent = false; - - /* 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); - - if (make_consistent && r != NULL) - { - r->r_state = RT_CONSISTENT; - _dl_debug_state (); - LIBC_PROBE (map_failed, 2, nsid, r); - } - - _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; @@ -1093,7 +971,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. */ @@ -1386,15 +1264,6 @@ cannot enable executable stack as shared object requires"); 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. */ @@ -1419,6 +1288,23 @@ 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 +_ld_map_object_2 (struct link_map *l, int mode, + struct r_file_id id, const char *origname, + Lmid_t nsid, struct r_debug *r, + bool *make_consistent_p) +{ /* Set up the symbol hash table. */ _dl_setup_hash (l); @@ -1510,7 +1396,7 @@ cannot enable executable stack as shared object requires"); r->r_state = RT_ADD; _dl_debug_state (); LIBC_PROBE (map_start, 2, nsid, r); - make_consistent = true; + *make_consistent_p = true; } else assert (r->r_state == RT_ADD); @@ -1520,10 +1406,157 @@ 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; + struct r_debug *r = _dl_debug_update (nsid); + bool make_consistent = false; + + /* 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); + + if (make_consistent && r != NULL) + { + r->r_state = RT_CONSISTENT; + _dl_debug_state (); + LIBC_PROBE (map_failed, 2, nsid, r); + } + + _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 (_ld_map_object_1 (l, fd, fbp, mode, loader, stack_endp, &errval, + &errstring)) + goto lose; + + /* 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; + + _ld_map_object_2 (l, mode, id, origname, nsid, r, &make_consistent); return l; } - + /* Print search path. */ static void print_search_path (struct r_search_path_elem **list, -- 2.37.2