From patchwork Tue Apr 24 16:26:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivek Dasmohapatra X-Patchwork-Id: 26925 Received: (qmail 86940 invoked by alias); 24 Apr 2018 16:27:04 -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 86889 invoked by uid 89); 24 Apr 2018 16:27:03 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.2 spammy=accounting X-HELO: bhuna.collabora.co.uk From: =?UTF-8?q?Vivek=20Das=C2=A0Mohapatra?= To: libc-alpha@sourceware.org Subject: [RFC PATCH 3/5] elf/dl-object.c: Implement a helper function to clone link_map entries Date: Tue, 24 Apr 2018 17:26:52 +0100 Message-Id: <20180424162654.17761-4-vivek@collabora.com> In-Reply-To: <20180424162654.17761-1-vivek@collabora.com> References: <20180424162654.17761-1-vivek@collabora.com> Provides the minimal functionality needed to take an existing link_map entry and create a clone of it in the specified namespace. --- elf/dl-object.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++ sysdeps/generic/ldsodefs.h | 6 ++++ 2 files changed, 84 insertions(+) diff --git a/elf/dl-object.c b/elf/dl-object.c index b37bcc1295..53a257a9dd 100644 --- a/elf/dl-object.c +++ b/elf/dl-object.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -50,6 +51,83 @@ _dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid) __rtld_lock_unlock_recursive (GL(dl_load_write_lock)); } +/* Clone an existing link map entry into a new link map. */ +/* This is based on _dl_new_object, skipping the steps we know we won't need + because this is mostly just a shell for the l_real pointer holding the real + link map entry (normally l == l->l_real, but not for ld.so in non-main + link maps or RTLD_SHARED clones). + It also flags the clone by setting l_clone, and sets the the no-delete + flag in the original. */ +struct link_map * +internal_function +_dl_clone_object (struct link_map *old, int mode, Lmid_t nsid) +{ + const char *name; + struct link_map *new; + struct libname_list *newname; +#ifdef SHARED + /* See _dl_new_object for how this number is arrived at: */ + unsigned int na = GLRO(dl_naudit) ?: ((mode & __RTLD_OPENEXEC) ? DL_NNS : 0); + size_t audit_space = na * sizeof (new->l_audit[0]); +#else +# define audit_space 0 +#endif + + name = old->l_name; + + /* Don't clone a clone: Go to the progenitor. */ + while (old && old->l_clone) + old = old->l_real; + + if (old == NULL) + _dl_signal_error (EINVAL, name, NULL, N_("cannot clone NULL link_map")); + + /* Object already exists in the target namespace. This should get handled + by dl_open_worker but just in case we get this far, handle it: */ + if (__glibc_unlikely (old->l_ns == nsid)) + { + /* Not actually possible, given the sanity checks above. */ + if (old->l_clone) + return old; + + _dl_signal_error (EEXIST, name, NULL, + N_("object cannot be demoted to a clone")); + } + + /* Now duplicate as little of _dl_new_object as possible to get a + working cloned object in the target link map. */ + new = (struct link_map *) calloc (sizeof (*new) + audit_space + + sizeof (struct link_map *) + + sizeof (*newname) + PATH_MAX, 1); + + /* Specific to the clone. */ + new->l_real = old; + new->l_clone = 1; + new->l_ns = nsid; + + /* Copied from the origin. */ + new->l_libname = old->l_libname; + new->l_name = old->l_name; + new->l_type = old->l_type; + + if (__glibc_unlikely (mode & RTLD_NODELETE)) + new->l_flags_1 |= DF_1_NODELETE; + + /* Specific to the origin. Ideally we'd do some accounting here but + for now it's easier to pin the original so the clone remains valid. */ + old->l_flags_1 |= DF_1_NODELETE; + + /* Fix up the searchlist so that relocations work. */ + /* TODO: figure out if we should call _dl_map_object_deps + or copy the contents of l_scope, l_searchlist et al. */ + _dl_map_object_deps (new, NULL, 0, 0, + mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT)); + + /* And finally put the clone into the target namespace. */ + _dl_add_to_namespace_list (new, nsid); + + return new; +} /* Allocate a `struct link_map' for a new object being loaded, and enter it into the _dl_loaded list. */ diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 5e1b24ecb5..dbd7507764 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -913,6 +913,12 @@ extern lookup_t _dl_lookup_symbol_x (const char *undef, extern void _dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid) attribute_hidden; +/* Clone an existing link map entry into a new link map */ +extern struct link_map *_dl_clone_object (struct link_map *old, + int mode, + Lmid_t nsid) + internal_function attribute_hidden; + /* Allocate a `struct link_map' for a new object being loaded. */ extern struct link_map *_dl_new_object (char *realname, const char *libname, int type, struct link_map *loader,