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

Message ID 20200626193228.1953-2-danielwa@cisco.com
State New
Headers show
Series
  • implement dlmopen hooks for gdb
Related show

Commit Message

H.J. Lu via Libc-alpha June 26, 2020, 7:32 p.m.
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(-)

-- 
2.17.1

Comments

H.J. Lu via Libc-alpha June 26, 2020, 9:17 p.m. | #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));

>  

> 



-- 
Cheers,
Carlos.

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