[RFC,v5,11/16] Use the DSO search helper to check for preloaded DT_GNU_UNIQUE DSOs

Message ID 20200617140024.12777-12-vivek@collabora.com
State New
Headers show
Series
  • Proof-of-Concept implementation of RTLD_SHARED for dlmopen
Related show

Commit Message

Adhemerval Zanella via Libc-alpha June 17, 2020, 2 p.m.
If a DSO already exists (with the same name) in the base namespace
and it is flagged DT_GNU_UNIQUE then we should behave as if a proxy
had been requested.
---
 elf/dl-load.c |  2 +-
 elf/dl-open.c | 20 +++++++++++++++++++-
 2 files changed, 20 insertions(+), 2 deletions(-)

-- 
2.11.0

Patch

diff --git a/elf/dl-load.c b/elf/dl-load.c
index 62820167d5..66848f8434 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -950,7 +950,7 @@  _dl_map_object_from_fd (const char *name, const char *origname, int fd,
       for (l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; l != NULL; l = l->l_next)
         if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id))
           {
-            if (!(l->l_flags_1 & DF_1_UNIQUE))
+            if (l->l_info[VALIDX (DT_GNU_UNIQUE)] == NULL)
               continue;
 
             /* Already loaded. Bump its reference count and return it.  */
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 75dc3893d3..43597a510e 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -476,6 +476,7 @@  dl_open_worker (void *a)
   const char *file = args->file;
   int mode = args->mode;
   struct link_map *call_map = NULL;
+  struct link_map *preloaded = NULL;
   int want_proxy = mode & RTLD_SHARED;
   Lmid_t proxy_ns = LM_ID_BASE;
 
@@ -519,6 +520,23 @@  dl_open_worker (void *a)
      may not be true if this is a recursive call to dlopen.  */
   _dl_debug_initialize (0, args->nsid);
 
+  /* Target Lmid is not the base and we haven't explicitly asked for a proxy:
+     We need to check for a matching DSO in the base Lmid in case it is flagged
+     DT_GNU_UNIQUE in which case we add RTLD_SHARED to the mode and set
+     want_proxy.
+     NOTE: RTLD_ISOLATE in the mode suppresses this behaviour.  */
+  if (__glibc_unlikely (args->nsid != LM_ID_BASE) &&
+      __glibc_likely (!want_proxy))
+    {
+      preloaded = _dl_find_dso (file, LM_ID_BASE);
+
+      if (preloaded && (preloaded->l_info[VALIDX (DT_GNU_UNIQUE)] != NULL))
+        {
+          want_proxy = RTLD_SHARED;
+          mode |= RTLD_SHARED;
+        }
+    }
+
   /* Load the named object.  */
   struct link_map *new;
   args->map = new = _dl_map_object (call_map, file, lt_loaded, 0,
@@ -548,7 +566,7 @@  dl_open_worker (void *a)
       return;
     }
 
-  /* If we were trying to load a DF_1_UNIQUE flagged DSO which was NOT
+  /* If we were trying to load a DT_GNU_UNIQUE flagged DSO which was NOT
      ALREADY LOADED (or not loaded with the name we are using) then
      _dl_map_object will return an instance from the main namespace.
      We need to detect this and set up the RTLD_SHARED flags.  */