From patchwork Mon Aug 20 13:54:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Vivek Dasmohapatra X-Patchwork-Id: 28978 Received: (qmail 95746 invoked by alias); 20 Aug 2018 14:01:08 -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 94820 invoked by uid 89); 20 Aug 2018 14:00:50 -0000 Authentication-Results: sourceware.org; auth=none 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, TIME_LIMIT_EXCEEDED autolearn=unavailable version=3.3.2 spammy=user's, logging, Further, opening X-HELO: bhuna.collabora.co.uk From: =?UTF-8?q?Vivek=20Das=C2=A0Mohapatra?= To: libc-alpha@sourceware.org Subject: [RFC][PATCH v3 4/6] elf/dl-load.c, elf-dl-open.c: Implement RTLD_SHARED dlmopen proxying Date: Mon, 20 Aug 2018 14:54:29 +0100 Message-Id: <5b38bdbe15f0956092f7237c3c0dd80615e977fb.1534532485.git.vivek@collabora.com> In-Reply-To: References: MIME-Version: 1.0 In-Reply-To: References: This uses the new infrastructure to implement RTLD_SHARED object proxying via dlmopen: Instead of opening the specified object in the requested namespace we open it in the main namespace (if it is not already present there) and proxy it to the destination. The following rules apply: If a proxy of the object is already present in the requested namespace, we simply return it (with an incremented direct-open count). If the object is already present in the requested namespace, a dl error is signalled, since we cannot satisfy the user's request. Proxies are never created in the main namespace: RTLD_SHARED has no effect when the requested namespace is LM_ID_BASE. --- elf/dl-load.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ elf/dl-open.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index 431236920f..6364030168 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1848,6 +1848,37 @@ open_path (const char *name, size_t namelen, int mode, return -1; } +/* Search for a link map proxy in the given namespace by name. + Consider it to be an error if the found object is not a proxy. */ +struct link_map * +_dl_find_proxy (Lmid_t nsid, const char *name) +{ + struct link_map *l; + + for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next) + { + if (__glibc_unlikely ((l->l_faked | l->l_removed) != 0)) + continue; + + if (!_dl_name_match_p (name, l)) + continue; + + /* We have a match - stop searching. */ + break; + } + + if (l) + { + if (l->l_proxy) + return l; + + _dl_signal_error (EEXIST, name, NULL, + N_("object cannot be demoted to a proxy")); + } + + return NULL; +} + /* Map in the shared object file NAME. */ struct link_map * @@ -1864,6 +1895,20 @@ _dl_map_object (struct link_map *loader, const char *name, assert (nsid >= 0); assert (nsid < GL(dl_nns)); +#ifdef SHARED + /* Only need to do proxy checks if `nsid' is not LM_ID_BASE. */ + if (__glibc_unlikely ((mode & RTLD_SHARED) && (nsid != LM_ID_BASE))) + { + /* Search the namespace in case the object is already proxied. */ + if((l = _dl_find_proxy (nsid, name)) != NULL) + return l; + + /* Further searches should be in the base ns: We will proxy the + resulting object in dl_open_worker *after* it is initialised. */ + nsid = LM_ID_BASE; + } +#endif + /* Look for this name among those already loaded. */ for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next) { diff --git a/elf/dl-open.c b/elf/dl-open.c index 9dde4acfbc..d28c2d2b7a 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -183,6 +183,8 @@ dl_open_worker (void *a) const char *file = args->file; int mode = args->mode; struct link_map *call_map = NULL; + int want_proxy = mode & RTLD_SHARED; + Lmid_t proxy_ns = LM_ID_BASE; /* Determine the caller's map if necessary. This is needed in case we have a DST, when we don't know the namespace ID we have to put @@ -237,6 +239,24 @@ dl_open_worker (void *a) /* This object is directly loaded. */ ++new->l_direct_opencount; + /* Proxy already existed in the target ns, nothing left to do. */ + if (__glibc_unlikely (new->l_proxy)) + { + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) + _dl_debug_printf ("proxied file=%s [%lu]; direct_opencount=%u\n\n", + new->l_name, new->l_ns, new->l_direct_opencount); + return; + } + + /* If we want proxy and we get this far then the entry in ‘new’ will + be in the main namespace: we should revert to the main namespace code + path(s), but remember the namespace we want the proxy to be in. */ + if (__glibc_unlikely (want_proxy)) + { + proxy_ns = args->nsid; + args->nsid = LM_ID_BASE; + } + /* It was already open. */ if (__glibc_unlikely (new->l_searchlist.r_list != NULL)) { @@ -252,6 +272,16 @@ dl_open_worker (void *a) assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT); + if (__glibc_unlikely (want_proxy)) + { + args->map = new = _dl_new_proxy (new, mode, proxy_ns); + ++new->l_direct_opencount; + + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) + _dl_debug_printf ("proxying file=%s [%lu]; direct_opencount=%u\n\n", + new->l_name, new->l_ns, new->l_direct_opencount); + } + return; } @@ -509,6 +539,14 @@ TLS generation counter wrapped! Please report this.")); /* It failed. */ return; + if (__glibc_unlikely (want_proxy)) + { + /* args->map is the return slot which the caller sees, but keep + the original value of new hanging around so we can see the + real link map entry (for logging etc). */ + args->map = _dl_new_proxy (new, mode, proxy_ns); + ++args->map->l_direct_opencount; + } #ifndef SHARED /* We must be the static _dl_open in libc.a. A static program that has loaded a dynamic object now has competition. */ @@ -517,8 +555,16 @@ TLS generation counter wrapped! Please report this.")); /* Let the user know about the opencount. */ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) - _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n", - new->l_name, new->l_ns, new->l_direct_opencount); + { + _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n", + new->l_name, new->l_ns, new->l_direct_opencount); + + if (args->map->l_proxy) + _dl_debug_printf ("proxying file=%s [%lu]; direct_opencount=%u\n\n", + args->map->l_name, + args->map->l_ns, + args->map->l_direct_opencount); + } }