[RFC,1/3] Segfault when dlopen with RTLD_GLOBAL in dlmopened library

Message ID 20200626193228.1953-2-danielwa@cisco.com
State New, archived
Headers
Series implement dlmopen hooks for gdb |

Commit Message

Daniel Walker June 26, 2020, 7:32 p.m. UTC
  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

Carlos O'Donell June 26, 2020, 9:17 p.m. UTC | #1
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));
>  
>
  

Patch

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));