From patchwork Mon Jan 6 15:44:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Viennot X-Patchwork-Id: 37214 Received: (qmail 43408 invoked by alias); 6 Jan 2020 15:44:24 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 43400 invoked by uid 89); 6 Jan 2020 15:44:24 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-20.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 spammy= X-HELO: mxo1.nje.dmz.twosigma.com From: Nicolas Viennot To: "libc-alpha@sourceware.org" Subject: [PATCH 2/3] dl-load: enforce soname uniqueness of loaded libraries Date: Mon, 6 Jan 2020 15:44:20 +0000 Message-ID: <8a449dd92e5f41189f95abbe803c82e3@EXMBDFT10.ad.twosigma.com> MIME-Version: 1.0 When loading a new library of name `libname`, the loader currently checks if any of the already loaded libraries have the soname `libname`. If so, it returns the already loaded library of soname `libname`. If not, it checks for the corresponding file `libname` on disk and compares the device and inode number of already loaded libraries. If there is a match, it returns the already loaded library of the same inode number. If not, it proceeds to load the library of path is `libname`. This patch adds the additional check of comparing the soname of the newly loaded library with the sonames of already loaded libraries. This new behavior enforces that no two loaded libaries have the same soname, bringing a sane property in the system. Note that this edge case can be encountered during a system upgrade, or when using certain configuration of file system mounts, where inodes cannot be relied upon. --- elf/dl-load.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/elf/dl-load.c b/elf/dl-load.c index c436a447af..c5c997f95b 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -851,6 +851,8 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l, _dl_signal_error (code, name, NULL, msg); } +static struct link_map * +_dl_find_object_from_name(const char *name, Lmid_t nsid); /* Map in the shared object NAME, actually located in REALNAME, and already opened on FD. */ @@ -1202,6 +1204,52 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, elf_get_dynamic_info (l, NULL); + /* + * Check if we have a loaded object with the same soname. If that's the + * case, return the previously loaded object. The loop follows a similar + * logic compared to the beginning of _dl_map_object(). + * the loader assumes that the sonames of loaded objects are without + * duplicates. + */ + + if (l->l_info[DT_SONAME] != NULL) + { + static struct link_map *_l; + const char *soname; + + soname = (((const char *) D_PTR (l, l_info[DT_STRTAB]) + + l->l_info[DT_SONAME]->d_un.d_val)); + + _l = _dl_find_object_from_name(soname, nsid); + if (__glibc_unlikely(_l != NULL)) + { + /* Free current object */ + _dl_unmap_segments (l); + + if (!l->l_libname->dont_free) + free (l->l_libname); + + if (l->l_phdr_allocated) + free ((void *) l->l_phdr); + + __close_nocancel (fd); + if (l->l_origin != (char *) -1l) + free ((char *) l->l_origin); + free (l); + free (realname); + + if (make_consistent) + { + r->r_state = RT_CONSISTENT; + _dl_debug_state (); + } + + /* Cache the name and return the previously loaded object */ + add_name_to_object (_l, name); + return _l; + } + } + /* Make sure we are not dlopen'ing an object that has the DF_1_NOOPEN flag set, or a PIE object. */ if ((__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN)