[RFC][PATCH v8 04/20] elf/dl-load.c, elf-dl-open.c: Implement RTLD_SHARED dlmopen proxying
Adhemerval Zanella
adhemerval.zanella@linaro.org
Mon Feb 15 14:53:18 GMT 2021
On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> 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 | 46 +++++++++++++++++++++++++++++++++++++++
> elf/dl-open.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 104 insertions(+), 2 deletions(-)
>
> diff --git a/elf/dl-load.c b/elf/dl-load.c
> index 9e2089cfaa..3c5f667717 100644
> --- a/elf/dl-load.c
> +++ b/elf/dl-load.c
> @@ -2006,6 +2006,38 @@ 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)
No implicit checks (even though this originated from ancient code).
for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
> + {
> + if (__glibc_unlikely ((l->l_faked | l->l_removed) != 0))
> + continue;
> +
> + if (!_dl_name_match_p (name, l))
> + continue;
Ok (although it would make sense to change _dl_name_match_p to
return a bool).
> +
> + /* We have a match - stop searching. */
> + break;
> + }
> +
> + if (l)
No implicit checks.
> + {
> + 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. */
>
Ok.
> struct link_map *
> @@ -2022,6 +2054,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. */
I am not sure if grave accent should be used on newer code (afaik our
git commit hooks refuses it on commit messages).
> + 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)
Space after 'if'. Also I think it usual to not put attribution inside an
if:
l = _dl_find_proxy (nsid, name);
if (l != NULL)
return l;
> + 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 ab7aaa345e..4cb90bfe19 100644
> --- a/elf/dl-open.c
> +++ b/elf/dl-open.c
> @@ -484,6 +484,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;
Use 'bool' here.
> + 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
> @@ -508,6 +510,15 @@ dl_open_worker (void *a)
> args->nsid = call_map->l_ns;
> }
>
> + /* Now that we know the NS for sure, sanity check the mode. */
> + if (__glibc_likely(args->nsid == LM_ID_BASE) &&
Space '__glibc_likely' and '__glibc_unlikely'.
> + __glibc_unlikely(mode & RTLD_SHARED))
> + {
> + args->mode &= ~RTLD_SHARED;
> + mode &= ~RTLD_SHARED;
> + want_proxy = 0;
> + }
> +
> /* The namespace ID is now known. Keep track of whether libc.so was
> already loaded, to determine whether it is necessary to call the
> early initialization routine (or clear libc_map on error). */
> @@ -541,6 +552,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
As before I think it should use apostrophe instead of grave accent.
> + 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))
> {
Ok.
> @@ -572,6 +601,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;
> }
>
OK.
> @@ -787,10 +826,27 @@ dl_open_worker (void *a)
> if (mode & RTLD_GLOBAL)
> add_to_global_update (new);
>
> + 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;
> + }
> +
> /* 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);
> + }
> }
>
> void *
>
Ok.
More information about the Libc-alpha
mailing list