[RFC,1/3] Segfault when dlopen with RTLD_GLOBAL in dlmopened library
Commit Message
From: Conan C Huang <conhuang@cisco.com>
GLIBC Bugzilla: 18684
When a dlmopenend library calls dlopen with RTLD_GLOBAL flag,
dynamic loader segfaults. Loader is trying to add new linkmap into
new namespaces _ns_main_searchlist. But this _ns_main_searchlist is
not initialized during dmopen call (when namespace was created).
Loader needs to initialize _ns_main_searchlist during dlmopen when a
new namespace is created. As well as clean up when that namespace is
deleted.
---
elf/dl-close.c | 7 ++++++-
elf/dl-open.c | 4 ++++
2 files changed, 10 insertions(+), 1 deletion(-)
Comments
On 6/26/20 3:32 PM, Daniel Walker via Libc-alpha wrote:
> From: Conan C Huang <conhuang@cisco.com>
>
> GLIBC Bugzilla: 18684
>
> When a dlmopenend library calls dlopen with RTLD_GLOBAL flag,
> dynamic loader segfaults. Loader is trying to add new linkmap into
> new namespaces _ns_main_searchlist. But this _ns_main_searchlist is
> not initialized during dmopen call (when namespace was created).
>
> Loader needs to initialize _ns_main_searchlist during dlmopen when a
> new namespace is created. As well as clean up when that namespace is
> deleted.
This implies that dlopen with RTLD_GLOBAL in a namespace applies only
to the global symbols of that namespace and that it does not promote
such a dlopen to the actual LM_ID_BASE global symbols.
Please see similar discussions about this from 2015:
https://sourceware.org/legacy-ml/libc-alpha/2015-07/msg00474.html
This will need tests to verify the change in behaviour is as we expect.
> ---
> elf/dl-close.c | 7 ++++++-
> elf/dl-open.c | 4 ++++
> 2 files changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/elf/dl-close.c b/elf/dl-close.c
> index 73b2817bbf..675f2fbac8 100644
> --- a/elf/dl-close.c
> +++ b/elf/dl-close.c
> @@ -802,7 +802,12 @@ _dl_close_worker (struct link_map *map, bool force)
> if (__builtin_expect (ns->_ns_loaded == NULL, 0)
> && nsid == GL(dl_nns) - 1)
> do
> - --GL(dl_nns);
> + {
> + --GL(dl_nns);
> +
> + /* Clear main search list */
> + GL(dl_ns)[GL(dl_nns)]._ns_main_searchlist = NULL;
> + }
> while (GL(dl_ns)[GL(dl_nns) - 1]._ns_loaded == NULL);
>
> /* Notify the debugger those objects are finalized and gone. */
> diff --git a/elf/dl-open.c b/elf/dl-open.c
> index 8769e47051..9b3606c491 100644
> --- a/elf/dl-open.c
> +++ b/elf/dl-open.c
> @@ -921,6 +921,10 @@ no more namespaces available for dlmopen()"));
>
> assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
>
> + /* Initialize main search list in new namespace */
> + if (__glibc_unlikely (GL(dl_ns)[nsid]._ns_main_searchlist == NULL))
> + GL(dl_ns)[nsid]._ns_main_searchlist = &(args.map->l_searchlist);
> +
> /* Release the lock. */
> __rtld_lock_unlock_recursive (GL(dl_load_lock));
>
>
@@ -802,7 +802,12 @@ _dl_close_worker (struct link_map *map, bool force)
if (__builtin_expect (ns->_ns_loaded == NULL, 0)
&& nsid == GL(dl_nns) - 1)
do
- --GL(dl_nns);
+ {
+ --GL(dl_nns);
+
+ /* Clear main search list */
+ GL(dl_ns)[GL(dl_nns)]._ns_main_searchlist = NULL;
+ }
while (GL(dl_ns)[GL(dl_nns) - 1]._ns_loaded == NULL);
/* Notify the debugger those objects are finalized and gone. */
@@ -921,6 +921,10 @@ no more namespaces available for dlmopen()"));
assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
+ /* Initialize main search list in new namespace */
+ if (__glibc_unlikely (GL(dl_ns)[nsid]._ns_main_searchlist == NULL))
+ GL(dl_ns)[nsid]._ns_main_searchlist = &(args.map->l_searchlist);
+
/* Release the lock. */
__rtld_lock_unlock_recursive (GL(dl_load_lock));