unofficial mirror of libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen
@ 2020-03-30 17:43 Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 01/15] Declare and describe the dlmopen RTLD_SHARED flag Vivek Das Mohapatra via Libc-alpha
                   ` (14 more replies)
  0 siblings, 15 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

This is a revision of a previous patchset that I posted here
regarding https://sourceware.org/bugzilla/show_bug.cgi?id=22745 

Since it has been some time since I had a chance to work on this
I will recap the previous introduction;

=======================================================================
  As discussed in the URL above dlmopen requires a mechanism for
  [optionally] sharing some objects between more than one namespace.

  The following patchset attempts an implementation for this: If an
  object is loaded with the new RTLD_SHARED flag we instead ensure
  that a "master" copy exists (and is flagged as no-delete) in the
  main namespace and a thin wrapper or clone is placed in the target
  namespace.

  This patch series should address all the comments received on the
  earlier (v1) series, and fixes a bug in the previous (v2) series
  which left the r_debug struct in an inconsistent state when creating
  a proxy triggered the initial load of a DSO into the main namespace.
=======================================================================

In addition this patch series now mplements the following:

 - dlmopen will implicitly apply RTLD_SHARED to the libc/libpthread group
   (requires a patched binutils/ld so that the libc family of DSOs can
   be flagged as requiring this behaviour)

 - LD_AUDIT paths will not apply this implict sharing rule, so audit libraries
   will continue to be completely isolated.

Currently the user cannot suppress this implicit sharing but that
could easily be achieved by renaming __RTLD_ISOLATE to RTLD_ISOLATE
and potting it with the other public dlopen/dlmopen mode flags.

I have not yet implemented, but plan to address once this series is
accepted/acceptable:

 - Sensible RTLD_GLOBAL semantics for dlmopened DSOs in non-base namespaces

 - dl_iterate_ns_phdr (cf dl_iterate_phdr but taking a namespace argument)

Vivek Das Mohapatra (15):
  Declare and describe the dlmopen RTLD_SHARED flag
  include/link.h: Update the link_map struct to allow proxies
  elf/dl-object.c: Implement a helper function to proxy link_map entries
  elf/dl-load.c, elf-dl-open.c: Implement RTLD_SHARED dlmopen proxying
  elf/dl-fini.c: Handle proxy link_map entries in the shutdown path
  elf/dl-init.c: Skip proxied link map entries in the dl init path
  Define a new DT_FLAGS_1 flag - DF_1_UNIQUE
  Abstract the loaded-DSO search code into a private helper function
  Compare loaded DSOs by file ID and check for DF_1_UNIQUE
  Use the new DSO finder helper function since we have it
  Use the DSO search helper to check for preloaded DF_1_UNIQUE DSOs
  When loading new DSOs into alternate namespaces check for DF_1_UNIQUE
  Suppress inter-namespace DSO sharing for audit libraries
  dlsym, dlvsym should be able to look up symbols via DSO proxies
  Add the DT_FLAGS_1 DF_1_UNIQUE flag to the glibc cluster

 Makeconfig                 |   1 +
 Makerules                  |   2 +-
 bits/dlfcn.h               |   7 ++
 elf/dl-close.c             |  43 ++++++----
 elf/dl-fini.c              |   6 +-
 elf/dl-init.c              |   4 +-
 elf/dl-load.c              | 208 +++++++++++++++++++++++++++++++++++++++------
 elf/dl-object.c            |  84 ++++++++++++++++++
 elf/dl-open.c              |  90 +++++++++++++++++++-
 elf/dl-sym.c               |  14 +++
 elf/elf.h                  |   1 +
 elf/rtld.c                 |   2 +-
 iconvdata/Makefile         |   1 +
 include/dlfcn.h            |   1 +
 include/elf.h              |   2 +-
 include/link.h             |   6 +-
 nptl/Makefile              |   2 +-
 sysdeps/generic/ldsodefs.h |   9 ++
 sysdeps/mips/bits/dlfcn.h  |   7 ++
 19 files changed, 435 insertions(+), 55 deletions(-)

-- 
2.11.0


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 01/15] Declare and describe the dlmopen RTLD_SHARED flag
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 02/15] include/link.h: Update the link_map struct to allow proxies Vivek Das Mohapatra via Libc-alpha
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

This flag will instruct dlmopen to create a shared object present
in the main namespace and accessible from the selected namespace
when supplied in the MODE argument.
---
 bits/dlfcn.h              | 7 +++++++
 sysdeps/mips/bits/dlfcn.h | 7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/bits/dlfcn.h b/bits/dlfcn.h
index ed67f29bc3..9170059323 100644
--- a/bits/dlfcn.h
+++ b/bits/dlfcn.h
@@ -32,6 +32,13 @@
    visible as if the object were linked directly into the program.  */
 #define RTLD_GLOBAL	0x00100
 
+/* If the following bit is set in the MODE argument to dlmopen
+   then the target object is loaded into the main namespace (if
+   it is not already there) and a shallow copy (proxy) is placed
+   in the target namespace: This allows multiple namespaces to
+   share a single instance of a DSO.  */
+#define RTLD_SHARED 0x00080
+
 /* Unix98 demands the following flag which is the inverse to RTLD_GLOBAL.
    The implementation does this by default and so we can define the
    value to zero.  */
diff --git a/sysdeps/mips/bits/dlfcn.h b/sysdeps/mips/bits/dlfcn.h
index e55262f3aa..fc33fd184e 100644
--- a/sysdeps/mips/bits/dlfcn.h
+++ b/sysdeps/mips/bits/dlfcn.h
@@ -32,6 +32,13 @@
    visible as if the object were linked directly into the program.  */
 #define RTLD_GLOBAL	0x0004
 
+/* If the following bit is set in the MODE argument to dlmopen
+   then the target object is loaded into the main namespace (if
+   it is not already there) and a shallow copy (proxy) is placed
+   in the target namespace: This allows multiple namespaces to
+   share a single instance of a DSO.  */
+#define RTLD_SHARED 0x00020
+
 /* Unix98 demands the following flag which is the inverse to RTLD_GLOBAL.
    The implementation does this by default and so we can define the
    value to zero.  */
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 02/15] include/link.h: Update the link_map struct to allow proxies
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 01/15] Declare and describe the dlmopen RTLD_SHARED flag Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 03/15] elf/dl-object.c: Implement a helper function to proxy link_map entries Vivek Das Mohapatra via Libc-alpha
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

We already have an l_real pointer, used for a similar purpose by
the linker for copies of ld.so in secondary namespaces. Update its
documentation and add a bitfield to indicate when link_map entry
is a proxy.
---
 include/link.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/link.h b/include/link.h
index aea268439c..c63166317d 100644
--- a/include/link.h
+++ b/include/link.h
@@ -103,8 +103,9 @@ struct link_map
        They may change without notice.  */
 
     /* This is an element which is only ever different from a pointer to
-       the very same copy of this type for ld.so when it is used in more
-       than one namespace.  */
+       the very same copy of this type when:
+       - A shallow copy of ld.so is placed in namespaces other than LM_ID_BASE.
+       - An object is proxied into a namespace by dlmopen with RTLD_SHARED.  */
     struct link_map *l_real;
 
     /* Number of the namespace this link map belongs to.  */
@@ -176,6 +177,7 @@ struct link_map
     unsigned int l_relocated:1;	/* Nonzero if object's relocations done.  */
     unsigned int l_init_called:1; /* Nonzero if DT_INIT function called.  */
     unsigned int l_global:1;	/* Nonzero if object in _dl_global_scope.  */
+    unsigned int l_proxy:1;    /* Nonzero if object is a shallow copy.  */
     unsigned int l_reserved:2;	/* Reserved for internal use.  */
     unsigned int l_phdr_allocated:1; /* Nonzero if the data structure pointed
 					to by `l_phdr' is allocated.  */
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 03/15] elf/dl-object.c: Implement a helper function to proxy link_map entries
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 01/15] Declare and describe the dlmopen RTLD_SHARED flag Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 02/15] include/link.h: Update the link_map struct to allow proxies Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 04/15] elf/dl-load.c, elf-dl-open.c: Implement RTLD_SHARED dlmopen proxying Vivek Das Mohapatra via Libc-alpha
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

Provides the minimal functionality needed to take an existing
link_map entry and create a proxy for it in the specified namespace.
---
 elf/dl-object.c            | 84 ++++++++++++++++++++++++++++++++++++++++++++++
 sysdeps/generic/ldsodefs.h |  5 +++
 2 files changed, 89 insertions(+)

diff --git a/elf/dl-object.c b/elf/dl-object.c
index d2cdf135cc..2ee5eee13c 100644
--- a/elf/dl-object.c
+++ b/elf/dl-object.c
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <ldsodefs.h>
+#include <libintl.h>
 
 #include <assert.h>
 
@@ -50,6 +51,89 @@ _dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid)
   __rtld_lock_unlock_recursive (GL(dl_load_write_lock));
 }
 
+/* Proxy an existing link map entry into a new link map:
+   This is based on _dl_new_object, skipping the steps we know we won't need
+   because this is mostly just a shell for the l_real pointer holding the real
+   link map entry (normally l == l->l_real, but not for ld.so in non-main
+   link maps or RTLD_SHARED proxies).
+   It also flags the proxy by setting l_proxy, and sets the the no-delete
+   flag in the original if it is an lt_loaded.  */
+struct link_map *
+_dl_new_proxy (struct link_map *old, int mode, Lmid_t nsid)
+{
+  const char *name;
+  struct link_map *new;
+  struct libname_list *newname;
+#ifdef SHARED
+  unsigned int na = GLRO(dl_naudit);
+
+  if ((mode & __RTLD_OPENEXEC) != 0)
+    na = DL_NNS;
+
+  size_t audit_space = na * sizeof (struct auditstate);
+#else
+# define audit_space 0
+#endif
+
+  name = old->l_name;
+
+  /* Find the original link map entry if `old' is itself a proxy. */
+  while (old && old->l_proxy)
+    old = old->l_real;
+
+  if (old == NULL)
+    _dl_signal_error (EINVAL, name, NULL, N_("cannot proxy NULL link_map"));
+
+  /* Object already exists in the target namespace. This should get handled
+     by dl_open_worker but just in case we get this far, handle it:  */
+  if (__glibc_unlikely (old->l_ns == nsid))
+    {
+      /* Not actually possible, given the sanity checks above.  */
+      if (old->l_proxy)
+        return old;
+
+      _dl_signal_error (EEXIST, name, NULL,
+                        N_("existing object cannot be demoted to a proxy"));
+    }
+
+  /* Now duplicate as little of _dl_new_object as possible to get a
+     working proxied object in the target link map.  */
+  new = (struct link_map *) calloc (sizeof (*new) + audit_space
+                                    + sizeof (struct link_map *)
+                                    + sizeof (*newname) + PATH_MAX, 1);
+
+  if (new == NULL)
+      _dl_signal_error (ENOMEM, name, NULL,
+                        N_("cannot create shared object descriptor"));
+
+  /* Specific to the proxy.  */
+  new->l_real = old;
+  new->l_proxy = 1;
+  new->l_ns = nsid;
+
+  /* Copied from the origin.  */
+  new->l_libname = old->l_libname;
+  new->l_name = old->l_name;
+  /* Proxies are considered lt_loaded if the real entry type is lt_library.  */
+  new->l_type = (old->l_type == lt_library) ? lt_loaded : old->l_type;
+
+  if (__glibc_unlikely (mode & RTLD_NODELETE))
+    new->l_flags_1 |= DF_1_NODELETE;
+
+  /* Specific to the origin. Ideally we'd do some accounting here but
+     for now it's easier to pin the original so the proxy remains valid.  */
+  if (old->l_type == lt_loaded)
+      old->l_flags_1 |= DF_1_NODELETE;
+
+  /* Fix up the searchlist so that relocations work.  */
+  _dl_map_object_deps (new, NULL, 0, 0,
+		       mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT));
+
+  /* And finally put the proxy in the target namespace.  */
+  _dl_add_to_namespace_list (new, nsid);
+
+  return new;
+}
 
 /* Allocate a `struct link_map' for a new object being loaded,
    and enter it into the _dl_loaded list.  */
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 497938ffa2..d3113ff4d8 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -945,6 +945,11 @@ extern lookup_t _dl_lookup_symbol_x (const char *undef,
 				     struct link_map *skip_map)
      attribute_hidden;
 
+/* Proxy an existing link map entry into a new link map */
+extern struct link_map *_dl_new_proxy (struct link_map *old,
+                                       int mode,
+                                       Lmid_t nsid)
+     attribute_hidden;
 
 /* Add the new link_map NEW to the end of the namespace list.  */
 extern void _dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid)
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 04/15] elf/dl-load.c, elf-dl-open.c: Implement RTLD_SHARED dlmopen proxying
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (2 preceding siblings ...)
  2020-03-30 17:43 ` [RFC][PATCH v4 03/15] elf/dl-object.c: Implement a helper function to proxy link_map entries Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 05/15] elf/dl-fini.c: Handle proxy link_map entries in the shutdown path Vivek Das Mohapatra via Libc-alpha
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

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 | 51 +++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 95 insertions(+), 2 deletions(-)

diff --git a/elf/dl-load.c b/elf/dl-load.c
index a6b80f9395..221589e292 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1904,6 +1904,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)
+    {
+      if (__glibc_unlikely ((l->l_faked | l->l_removed) != 0))
+        continue;
+
+      if (!_dl_name_match_p (name, l))
+        continue;
+
+      /* We have a match - stop searching.  */
+      break;
+    }
+
+  if (l)
+    {
+      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.  */
 
 struct link_map *
@@ -1920,6 +1952,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.  */
+  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)
+        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 623c9754eb..92771638ab 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -476,6 +476,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;
+  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
@@ -528,6 +530,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
+     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))
     {
@@ -559,6 +579,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;
     }
 
@@ -762,6 +792,14 @@ 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;
+    }
 #ifndef SHARED
   /* We must be the static _dl_open in libc.a.  A static program that
      has loaded a dynamic object now has competition.  */
@@ -770,10 +808,19 @@ dl_open_worker (void *a)
 
   /* 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 *
 _dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid,
 	  int argc, char *argv[], char *env[])
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 05/15] elf/dl-fini.c: Handle proxy link_map entries in the shutdown path
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (3 preceding siblings ...)
  2020-03-30 17:43 ` [RFC][PATCH v4 04/15] elf/dl-load.c, elf-dl-open.c: Implement RTLD_SHARED dlmopen proxying Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 06/15] elf/dl-init.c: Skip proxied link map entries in the dl init path Vivek Das Mohapatra via Libc-alpha
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

When cleaning up before exit we should not call destructors or
otherwise free [most of] the contents of proxied link_map entries
since they share [most of] their contents with the LM_ID_BASE
objects to which they point.
---
 elf/dl-close.c | 43 ++++++++++++++++++++++++++-----------------
 elf/dl-fini.c  |  6 ++++--
 2 files changed, 30 insertions(+), 19 deletions(-)

diff --git a/elf/dl-close.c b/elf/dl-close.c
index 73b2817bbf..a4c1a92ee7 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -283,8 +283,9 @@ _dl_close_worker (struct link_map *map, bool force)
 
 	  /* Call its termination function.  Do not do it for
 	     half-cooked objects.  Temporarily disable exception
-	     handling, so that errors are fatal.  */
-	  if (imap->l_init_called)
+	     handling, so that errors are fatal.
+	     Proxies should never have this flag set, but we double check.  */
+	  if (imap->l_init_called && !imap->l_proxy)
 	    {
 	      /* When debugging print a message first.  */
 	      if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS,
@@ -360,7 +361,9 @@ _dl_close_worker (struct link_map *map, bool force)
 	     one for the terminating NULL pointer.  */
 	  size_t remain = (new_list != NULL) + 1;
 	  bool removed_any = false;
-	  for (size_t cnt = 0; imap->l_scope[cnt] != NULL; ++cnt)
+	  for (size_t cnt = 0;
+               imap->l_scope && imap->l_scope[cnt] != NULL;
+               ++cnt)
 	    /* This relies on l_scope[] entries being always set either
 	       to its own l_symbolic_searchlist address, or some map's
 	       l_searchlist address.  */
@@ -686,8 +689,10 @@ _dl_close_worker (struct link_map *map, bool force)
 
 	  /* We can unmap all the maps at once.  We determined the
 	     start address and length when we loaded the object and
-	     the `munmap' call does the rest.  */
-	  DL_UNMAP (imap);
+	     the `munmap' call does the rest. Proxies do not have
+             any segments of their own to unmap.  */
+          if (!imap->l_proxy)
+            DL_UNMAP (imap);
 
 	  /* Finally, unlink the data structure and free it.  */
 #if DL_NNS == 1
@@ -727,19 +732,23 @@ _dl_close_worker (struct link_map *map, bool force)
 	    _dl_debug_printf ("\nfile=%s [%lu];  destroying link map\n",
 			      imap->l_name, imap->l_ns);
 
-	  /* This name always is allocated.  */
-	  free (imap->l_name);
-	  /* Remove the list with all the names of the shared object.  */
+          /* Skip structures borrowed by proxies from the real map.  */
+          if (!imap->l_proxy)
+            {
+              /* This name always is allocated.  */
+              free (imap->l_name);
+              /* Remove the list with all the names of the shared object.  */
 
-	  struct libname_list *lnp = imap->l_libname;
-	  do
-	    {
-	      struct libname_list *this = lnp;
-	      lnp = lnp->next;
-	      if (!this->dont_free)
-		free (this);
-	    }
-	  while (lnp != NULL);
+              struct libname_list *lnp = imap->l_libname;
+              do
+                {
+                  struct libname_list *this = lnp;
+                  lnp = lnp->next;
+                  if (!this->dont_free)
+                    free (this);
+                }
+              while (lnp != NULL);
+            }
 
 	  /* Remove the searchlists.  */
 	  free (imap->l_initfini);
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index 226a6f077a..eb56923c7d 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -72,7 +72,7 @@ _dl_fini (void)
 	  assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL);
 	  for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next)
 	    /* Do not handle ld.so in secondary namespaces.  */
-	    if (l == l->l_real)
+	    if (l == l->l_real || l->l_proxy)
 	      {
 		assert (i < nloaded);
 
@@ -110,7 +110,9 @@ _dl_fini (void)
 	    {
 	      struct link_map *l = maps[i];
 
-	      if (l->l_init_called)
+              /* Do not call fini functions via proxies, or for
+                 objects which are not marked as initialised.  */
+	      if (l->l_init_called && !l->l_proxy)
 		{
 		  /* Make sure nothing happens if we are called twice.  */
 		  l->l_init_called = 0;
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 06/15] elf/dl-init.c: Skip proxied link map entries in the dl init path
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (4 preceding siblings ...)
  2020-03-30 17:43 ` [RFC][PATCH v4 05/15] elf/dl-fini.c: Handle proxy link_map entries in the shutdown path Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 07/15] Define a new DT_FLAGS_1 flag - DF_1_UNIQUE Vivek Das Mohapatra via Libc-alpha
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

Proxies should not trigger calls to DT_INIT constructors since they're
just shims that point to the real, already loaded and initialised, objects.
---
 elf/dl-init.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/elf/dl-init.c b/elf/dl-init.c
index 55d528c7a5..2eef584cf9 100644
--- a/elf/dl-init.c
+++ b/elf/dl-init.c
@@ -27,8 +27,8 @@ typedef void (*init_t) (int, char **, char **);
 static void
 call_init (struct link_map *l, int argc, char **argv, char **env)
 {
-  if (l->l_init_called)
-    /* This object is all done.  */
+  if (l->l_init_called || l->l_proxy)
+    /* This object is all done, or a proxy (and therefore initless).  */
     return;
 
   /* Avoid handling this constructor again in case we have a circular
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 07/15] Define a new DT_FLAGS_1 flag - DF_1_UNIQUE
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (5 preceding siblings ...)
  2020-03-30 17:43 ` [RFC][PATCH v4 06/15] elf/dl-init.c: Skip proxied link map entries in the dl init path Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 08/15] Abstract the loaded-DSO search code into a private helper function Vivek Das Mohapatra via Libc-alpha
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

We expect this flag to be set on ELF DSOs that should only
ever have one instance across all link map namespaces.

libc and its constituent DSOs should have this flag set.
---
 elf/elf.h     | 1 +
 include/elf.h | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/elf/elf.h b/elf/elf.h
index 2549a177d6..e0876b5701 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -997,6 +997,7 @@ typedef struct
 #define	DF_1_KMOD       0x10000000
 #define	DF_1_WEAKFILTER 0x20000000
 #define	DF_1_NOCOMMON   0x40000000
+#define	DF_1_UNIQUE     0x80000000      /* Object should exist at most once */
 
 /* Flags for the feature selection in DT_FEATURE_1.  */
 #define DTF_1_PARINIT	0x00000001
diff --git a/include/elf.h b/include/elf.h
index 14ed67ff67..ebcae81522 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -23,7 +23,7 @@
 # endif
 # define DT_1_SUPPORTED_MASK \
    (DF_1_NOW | DF_1_NODELETE | DF_1_INITFIRST | DF_1_NOOPEN \
-    | DF_1_ORIGIN | DF_1_NODEFLIB | DF_1_PIE)
+    | DF_1_ORIGIN | DF_1_NODEFLIB | DF_1_PIE | DF_1_UNIQUE)
 
 #endif /* !_ISOMAC */
 #endif /* elf.h */
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 08/15] Abstract the loaded-DSO search code into a private helper function
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (6 preceding siblings ...)
  2020-03-30 17:43 ` [RFC][PATCH v4 07/15] Define a new DT_FLAGS_1 flag - DF_1_UNIQUE Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 09/15] Compare loaded DSOs by file ID and check for DF_1_UNIQUE Vivek Das Mohapatra via Libc-alpha
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

---
 elf/dl-load.c              | 38 ++++++++++++++++++++++++++++++++++++++
 sysdeps/generic/ldsodefs.h |  4 ++++
 2 files changed, 42 insertions(+)

diff --git a/elf/dl-load.c b/elf/dl-load.c
index 221589e292..d4d6a6318b 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1936,6 +1936,44 @@ _dl_find_proxy (Lmid_t nsid, const char *name)
   return NULL;
 }
 
+/* search for a shared object in a given namespace.  */
+struct link_map *
+_dl_find_dso (const char *name, Lmid_t nsid)
+{
+  struct link_map *l;
+
+  for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
+    {
+      /* If the requested name matches the soname of a loaded object,
+	 use that object.  Elide this check for names that have not
+	 yet been opened.  */
+      if (__glibc_unlikely ((l->l_faked | l->l_removed) != 0))
+	continue;
+      if (!_dl_name_match_p (name, l))
+	{
+	  const char *soname;
+
+	  if (__glibc_likely (l->l_soname_added)
+	      || l->l_info[DT_SONAME] == NULL)
+	    continue;
+
+	  soname = ((const char *) D_PTR (l, l_info[DT_STRTAB])
+		    + l->l_info[DT_SONAME]->d_un.d_val);
+	  if (strcmp (name, soname) != 0)
+	    continue;
+
+	  /* We have a match on a new name -- cache it.  */
+	  add_name_to_object (l, soname);
+	  l->l_soname_added = 1;
+	}
+
+      /* We have a match.  */
+      return l;
+    }
+
+  return NULL;
+}
+
 /* Map in the shared object file NAME.  */
 
 struct link_map *
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index d3113ff4d8..3b5c5e9147 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1184,6 +1184,10 @@ extern void _dl_show_scope (struct link_map *new, int from)
 extern struct link_map *_dl_find_dso_for_object (const ElfW(Addr) addr);
 rtld_hidden_proto (_dl_find_dso_for_object)
 
+extern struct link_map *_dl_find_dso (const char *name, Lmid_t nsid);
+rtld_hidden_proto (_dl_find_dso)
+
+
 /* Initialization which is normally done by the dynamic linker.  */
 extern void _dl_non_dynamic_init (void)
      attribute_hidden;
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 09/15] Compare loaded DSOs by file ID and check for DF_1_UNIQUE
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (7 preceding siblings ...)
  2020-03-30 17:43 ` [RFC][PATCH v4 08/15] Abstract the loaded-DSO search code into a private helper function Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 10/15] Use the new DSO finder helper function since we have it Vivek Das Mohapatra via Libc-alpha
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

If _dl_map_object_from_fd finds that a DSO it was asked to
load into a non-base namespace is already loaded (into the
main namespace) and is flagged DF_1_UNIQUE then it should
return that DSO's link map entry.

In such cases _dl_open_worker must notice that this has
happened and dontinue down the link map proxy generation
path instead of normal link map entry preparation.
---
 elf/dl-load.c | 26 ++++++++++++++++++++++++++
 elf/dl-open.c | 10 ++++++++++
 2 files changed, 36 insertions(+)

diff --git a/elf/dl-load.c b/elf/dl-load.c
index d4d6a6318b..76970f79de 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -941,6 +941,32 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
     }
 #endif
 
+  /* DSOs in the main namespace which are flagged DF_1_UNIQUE should only
+     be opened into the main namespace. Other namespaces should only get
+     proxies.  */
+  if (__glibc_unlikely (nsid != LM_ID_BASE))
+    {
+      /* Check base ns to see if the name matched another already loaded.  */
+      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))
+              continue;
+
+            /* Already loaded. Bump its reference count and return it.  */
+            __close_nocancel (fd);
+
+            /* If the name is not listed for this object add it.  */
+            free (realname);
+            add_name_to_object (l, name);
+
+            /* NOTE: It is important that our caller picks up on the fact
+               that we have NOT returned an object in the requested namespace
+               and handles the proxying correctly */
+            return l;
+          }
+    }
+
   if (mode & RTLD_NOLOAD)
     {
       /* We are not supposed to load the object unless it is already
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 92771638ab..9265b4239a 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -539,6 +539,16 @@ dl_open_worker (void *a)
       return;
     }
 
+  /* If we were trying to load a DF_1_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.  */
+  if (__glibc_unlikely(args->nsid != LM_ID_BASE && new->l_ns == LM_ID_BASE))
+    {
+      want_proxy = RTLD_SHARED;
+      mode |= RTLD_SHARED;
+    }
+
   /* If we want proxy and we get this far then the entry in ‘new’ will
      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.  */
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 10/15] Use the new DSO finder helper function since we have it
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (8 preceding siblings ...)
  2020-03-30 17:43 ` [RFC][PATCH v4 09/15] Compare loaded DSOs by file ID and check for DF_1_UNIQUE Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 11/15] Use the DSO search helper to check for preloaded DF_1_UNIQUE DSOs Vivek Das Mohapatra via Libc-alpha
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

---
 elf/dl-load.c | 31 +++----------------------------
 1 file changed, 3 insertions(+), 28 deletions(-)

diff --git a/elf/dl-load.c b/elf/dl-load.c
index 76970f79de..62820167d5 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -2031,34 +2031,9 @@ _dl_map_object (struct link_map *loader, const char *name,
 #endif
 
   /* Look for this name among those already loaded.  */
-  for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
-    {
-      /* If the requested name matches the soname of a loaded object,
-	 use that object.  Elide this check for names that have not
-	 yet been opened.  */
-      if (__glibc_unlikely ((l->l_faked | l->l_removed) != 0))
-	continue;
-      if (!_dl_name_match_p (name, l))
-	{
-	  const char *soname;
-
-	  if (__glibc_likely (l->l_soname_added)
-	      || l->l_info[DT_SONAME] == NULL)
-	    continue;
-
-	  soname = ((const char *) D_PTR (l, l_info[DT_STRTAB])
-		    + l->l_info[DT_SONAME]->d_un.d_val);
-	  if (strcmp (name, soname) != 0)
-	    continue;
-
-	  /* We have a match on a new name -- cache it.  */
-	  add_name_to_object (l, soname);
-	  l->l_soname_added = 1;
-	}
-
-      /* We have a match.  */
-      return l;
-    }
+  l = _dl_find_dso (name, nsid);
+  if (l != NULL)
+    return l;
 
   /* Display information if we are debugging.  */
   if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 11/15] Use the DSO search helper to check for preloaded DF_1_UNIQUE DSOs
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (9 preceding siblings ...)
  2020-03-30 17:43 ` [RFC][PATCH v4 10/15] Use the new DSO finder helper function since we have it Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 12/15] When loading new DSOs into alternate namespaces check for DF_1_UNIQUE Vivek Das Mohapatra via Libc-alpha
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

If a DSO already exists (with the same name) in the base namespace
and it is flagged DF_1_UNIQUE then we should behave as if a proxy
had been requested.
---
 elf/dl-open.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/elf/dl-open.c b/elf/dl-open.c
index 9265b4239a..0197cd07e0 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;
 
@@ -510,6 +511,22 @@ 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
+     DF_1_UNIQUE in which case we add RTLD_SHARED to the mode and set
+     want_proxy.  */
+  if (__glibc_unlikely (args->nsid != LM_ID_BASE) &&
+      __glibc_likely (!want_proxy))
+    {
+      preloaded = _dl_find_dso (file, LM_ID_BASE);
+
+      if (preloaded && (preloaded->l_flags_1 & DF_1_UNIQUE))
+        {
+          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,
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 12/15] When loading new DSOs into alternate namespaces check for DF_1_UNIQUE
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (10 preceding siblings ...)
  2020-03-30 17:43 ` [RFC][PATCH v4 11/15] Use the DSO search helper to check for preloaded DF_1_UNIQUE DSOs Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 13/15] Suppress inter-namespace DSO sharing for audit libraries Vivek Das Mohapatra via Libc-alpha
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

If a DSO has not already been loaded and the target is not the main
namespace then we must check to see if it's been DF_1_UNIQUE tagged
and load it into the main namespace instead.

dl_open_worker has alread been modified to notice the discrepancy
between the request and the result in such cases, and will set up
a proxy in the target namespace.
---
 elf/dl-load.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 86 insertions(+), 14 deletions(-)

diff --git a/elf/dl-load.c b/elf/dl-load.c
index 62820167d5..a2d78f8615 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -827,6 +827,63 @@ _dl_init_paths (const char *llp)
     env_path_list.dirs = (void *) -1;
 }
 
+static ElfW(Word)
+_get_dt_flags (int fd, const ElfW(Ehdr) *header, const ElfW(Phdr) *phdr)
+{
+  ElfW(Word) flags = 0;
+  const ElfW(Phdr) *ph;
+  ElfW(Dyn) entry = {};
+  off_t reset;
+  off_t pos;
+  off_t end;
+
+  reset = __lseek (fd, 0, SEEK_CUR);
+
+  for (ph = phdr; ph < &phdr[header->e_phnum]; ++ph)
+    {
+      switch (ph->p_type)
+	{
+        case PT_DYNAMIC:
+          // dt_flags_1 = get_dt_flags_1( fd, ph->p_offset, ph->p_filesz );
+          pos = __lseek (fd, ph->p_offset, SEEK_SET);
+          end = pos + ph->p_filesz;
+
+          while (pos < end)
+            {
+              ssize_t rb = 0;
+              do
+                {
+                  ssize_t rretl = __read_nocancel (fd, &entry + rb,
+                                                   sizeof (ElfW(Dyn)) - rb);
+                  if (rretl <= 0)
+                    goto cleanup;
+
+                  rb += rretl;
+                }
+              while (__glibc_unlikely (rb < sizeof (ElfW(Dyn))));
+
+              switch (entry.d_tag)
+                {
+                case DT_FLAGS_1:
+                  flags = entry.d_un.d_val;
+                case DT_NULL:
+                  goto cleanup;
+                  break;
+                default:
+                  break;
+                }
+              pos += rb;
+            }
+          break;
+        }
+    }
+
+ cleanup:
+  /* Put the file descriptor offset back where it was when we were called.  */
+  __lseek (fd, reset, SEEK_SET);
+
+  return flags;
+}
 
 static void
 __attribute__ ((noreturn, noinline))
@@ -868,6 +925,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
   const ElfW(Ehdr) *header;
   const ElfW(Phdr) *phdr;
   const ElfW(Phdr) *ph;
+  ElfW(Word) dt_flags_1 = 0;
   size_t maplength;
   int type;
   /* Initialize to keep the compiler happy.  */
@@ -1019,6 +1077,34 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
   else
     assert (r->r_state == RT_ADD);
 
+  /* Load the ELF header using preallocated struct space if it's big enough.  */
+  maplength = header->e_phnum * sizeof (ElfW(Phdr));
+  if (header->e_phoff + maplength <= (size_t) fbp->len)
+    phdr = (void *) (fbp->buf + header->e_phoff);
+  else
+    {
+      phdr = alloca (maplength);
+      if ((size_t) __pread64_nocancel (fd, (void *) phdr, maplength,
+				       header->e_phoff) != maplength)
+	{
+	  errstring = N_("cannot read file data");
+	  goto call_lose_errno;
+	}
+    }
+
+  /* We need to check for DT_FLAGS_1 & DF_1_UNIQUE before we start
+     initialising any namespace dependent metatada.  */
+  if (nsid != LM_ID_BASE)
+    {
+      dt_flags_1 = _get_dt_flags (fd, header, phdr);
+
+      /* Target DSO is flagged as unique: Make sure it gets loaded into
+         the base namespace. It is up to our caller to generate a proxy in
+         the target nsid.  */
+      if (dt_flags_1 & DF_1_UNIQUE)
+        nsid = LM_ID_BASE;
+    }
+
   /* Enter the new object in the list of loaded objects.  */
   l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
   if (__glibc_unlikely (l == NULL))
@@ -1036,20 +1122,6 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
   type = header->e_type;
   l->l_phnum = header->e_phnum;
 
-  maplength = header->e_phnum * sizeof (ElfW(Phdr));
-  if (header->e_phoff + maplength <= (size_t) fbp->len)
-    phdr = (void *) (fbp->buf + header->e_phoff);
-  else
-    {
-      phdr = alloca (maplength);
-      if ((size_t) __pread64_nocancel (fd, (void *) phdr, maplength,
-				       header->e_phoff) != maplength)
-	{
-	  errstring = N_("cannot read file data");
-	  goto call_lose_errno;
-	}
-    }
-
    /* On most platforms presume that PT_GNU_STACK is absent and the stack is
     * executable.  Other platforms default to a nonexecutable stack and don't
     * need PT_GNU_STACK to do so.  */
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 13/15] Suppress inter-namespace DSO sharing for audit libraries
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (11 preceding siblings ...)
  2020-03-30 17:43 ` [RFC][PATCH v4 12/15] When loading new DSOs into alternate namespaces check for DF_1_UNIQUE Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 14/15] dlsym, dlvsym should be able to look up symbols via DSO proxies Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 15/15] Add the DT_FLAGS_1 DF_1_UNIQUE flag to the glibc cluster Vivek Das Mohapatra via Libc-alpha
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

Audit libraries should not participate in DSO sharing: In
particular libraries tagged with DF_1_UNIQUE should not be
shared between the audit namespace and any others - they
should get their own copy.

This is signalled to the loader code by passing an internal
__RTLD_ISOLATE flag from the relevant entry point in the dl
modes argument.
---
 elf/dl-load.c   |  5 +++--
 elf/dl-open.c   | 16 +++++++++++++---
 elf/rtld.c      |  2 +-
 include/dlfcn.h |  1 +
 4 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/elf/dl-load.c b/elf/dl-load.c
index a2d78f8615..a3d4fc2ce0 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1002,7 +1002,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
   /* DSOs in the main namespace which are flagged DF_1_UNIQUE should only
      be opened into the main namespace. Other namespaces should only get
      proxies.  */
-  if (__glibc_unlikely (nsid != LM_ID_BASE))
+  if (__glibc_unlikely ((nsid != LM_ID_BASE) && !(mode & __RTLD_ISOLATE)))
     {
       /* Check base ns to see if the name matched another already loaded.  */
       for (l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; l != NULL; l = l->l_next)
@@ -1094,7 +1094,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
 
   /* We need to check for DT_FLAGS_1 & DF_1_UNIQUE before we start
      initialising any namespace dependent metatada.  */
-  if (nsid != LM_ID_BASE)
+  if (__glibc_unlikely ((nsid != LM_ID_BASE) && !(mode & __RTLD_ISOLATE)))
     {
       dt_flags_1 = _get_dt_flags (fd, header, phdr);
 
@@ -2087,6 +2087,7 @@ _dl_map_object (struct link_map *loader, const char *name,
 
   assert (nsid >= 0);
   assert (nsid < GL(dl_nns));
+  assert (!((mode & __RTLD_ISOLATE) && (mode & RTLD_SHARED)));
 
 #ifdef SHARED
   /* Only need to do proxy checks if `nsid' is not LM_ID_BASE.  */
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 0197cd07e0..b3e9dbfe0d 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -477,9 +477,16 @@ dl_open_worker (void *a)
   int mode = args->mode;
   struct link_map *call_map = NULL;
   struct link_map *preloaded = NULL;
-  int want_proxy = mode & RTLD_SHARED;
+  int want_proxy = 0;
+  int dl_isolate = mode & __RTLD_ISOLATE;
   Lmid_t proxy_ns = LM_ID_BASE;
 
+  /* Isolation means we should suppress all inter-namespace sharing.  */
+  if (dl_isolate)
+      mode &= ~RTLD_SHARED;
+  else
+      want_proxy = mode & RTLD_SHARED;
+
   /* 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
      the new object in, or when the file name has no path in which
@@ -514,8 +521,10 @@ dl_open_worker (void *a)
   /* 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
      DF_1_UNIQUE in which case we add RTLD_SHARED to the mode and set
-     want_proxy.  */
+     want_proxy.
+     NOTE: __RTLD_ISOLATE in the mode suppresses this behaviour.  */
   if (__glibc_unlikely (args->nsid != LM_ID_BASE) &&
+      __glibc_likely (!dl_isolate) &&
       __glibc_likely (!want_proxy))
     {
       preloaded = _dl_find_dso (file, LM_ID_BASE);
@@ -626,7 +635,8 @@ dl_open_worker (void *a)
 
   /* Load that object's dependencies.  */
   _dl_map_object_deps (new, NULL, 0, 0,
-		       mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT));
+		       mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT |
+		               __RTLD_ISOLATE));
 
   /* So far, so good.  Now check the versions.  */
   for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
diff --git a/elf/rtld.c b/elf/rtld.c
index 553cfbd1b7..8b1734ed12 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -616,7 +616,7 @@ dlmopen_doit (void *a)
   struct dlmopen_args *args = (struct dlmopen_args *) a;
   args->map = _dl_open (args->fname,
 			(RTLD_LAZY | __RTLD_DLOPEN | __RTLD_AUDIT
-			 | __RTLD_SECURE),
+			 | __RTLD_SECURE | __RTLD_ISOLATE),
 			dl_main, LM_ID_NEWLM, _dl_argc, _dl_argv,
 			__environ);
 }
diff --git a/include/dlfcn.h b/include/dlfcn.h
index 93dd369ab1..6fb7a3c778 100644
--- a/include/dlfcn.h
+++ b/include/dlfcn.h
@@ -12,6 +12,7 @@
 #define __RTLD_AUDIT	0x08000000
 #define __RTLD_SECURE	0x04000000 /* Apply additional security checks.  */
 #define __RTLD_NOIFUNC	0x02000000 /* Suppress calling ifunc functions.  */
+#define __RTLD_ISOLATE  0x01000000 /* Suppress RTLD_SHARED and/or DF_1_UNIQUE */
 
 #define __LM_ID_CALLER	-2
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 14/15] dlsym, dlvsym should be able to look up symbols via DSO proxies
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (12 preceding siblings ...)
  2020-03-30 17:43 ` [RFC][PATCH v4 13/15] Suppress inter-namespace DSO sharing for audit libraries Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  2020-03-30 17:43 ` [RFC][PATCH v4 15/15] Add the DT_FLAGS_1 DF_1_UNIQUE flag to the glibc cluster Vivek Das Mohapatra via Libc-alpha
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

---
 elf/dl-sym.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/elf/dl-sym.c b/elf/dl-sym.c
index b43a50e544..2974efd60a 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -108,6 +108,10 @@ do_sym (void *handle, const char *name, void *who,
     {
       match = find_caller_link_map (caller);
 
+      /* Proxies don't contain any symbols: Need to look at the real DSO.  */
+      if (__glibc_unlikely (match->l_proxy))
+	match = match->l_real;
+
       /* Search the global scope.  We have the simple case where
 	 we look up in the scope of an object which was part of
 	 the initial binary.  And then the more complex part
@@ -152,6 +156,11 @@ RTLD_NEXT used in code not dynamically loaded"));
 	}
 
       struct link_map *l = match;
+
+      /* Proxies don't contain any symbols: Need to look at the real DSO.  */
+      if (__glibc_unlikely (l->l_proxy))
+	l = l->l_real;
+
       while (l->l_loader != NULL)
 	l = l->l_loader;
 
@@ -162,6 +171,11 @@ RTLD_NEXT used in code not dynamically loaded"));
     {
       /* Search the scope of the given object.  */
       struct link_map *map = handle;
+
+      /* Proxies don't contain any symbols: Need to look at the real DSO.  */
+      if (__glibc_unlikely (map->l_proxy))
+	map = map->l_real;
+
       result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
 					 vers, 0, flags, NULL);
     }
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC][PATCH v4 15/15] Add the DT_FLAGS_1 DF_1_UNIQUE flag to the glibc cluster
  2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (13 preceding siblings ...)
  2020-03-30 17:43 ` [RFC][PATCH v4 14/15] dlsym, dlvsym should be able to look up symbols via DSO proxies Vivek Das Mohapatra via Libc-alpha
@ 2020-03-30 17:43 ` Vivek Das Mohapatra via Libc-alpha
  14 siblings, 0 replies; 16+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2020-03-30 17:43 UTC (permalink / raw
  To: vivek, libc-alpha

---
 Makeconfig         | 1 +
 Makerules          | 2 +-
 iconvdata/Makefile | 1 +
 nptl/Makefile      | 2 +-
 4 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/Makeconfig b/Makeconfig
index f252842979..269050633c 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -398,6 +398,7 @@ LDFLAGS-lib.so += -Wl,-z,now
 # Extra flags for dynamically linked non-test main programs.
 link-extra-flags += -Wl,-z,now
 endif
+LDFLAGS-lib.so += -Wl,-z,unique
 
 # Command to run after every final link (executable or shared object).
 # This is invoked with $(call after-link,...), so it should operate on
diff --git a/Makerules b/Makerules
index 1e9c18f0d8..dccd9e3c54 100644
--- a/Makerules
+++ b/Makerules
@@ -635,7 +635,7 @@ build-shlib-objlist = $(build-module-helper-objlist) \
 # Don't try to use -lc when making libc.so itself.
 # Also omits crti.o and crtn.o, which we do not want
 # since we define our own `.init' section specially.
-LDFLAGS-c.so = -nostdlib -nostartfiles
+LDFLAGS-c.so = -nostdlib -nostartfiles -Wl,-z,unique
 # But we still want to link libc.so against $(libc.so-gnulib).
 LDLIBS-c.so += $(libc.so-gnulib)
 # Give libc.so an entry point and make it directly runnable itself.
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index c83962f351..338c8d0ff0 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -67,6 +67,7 @@ modules	:= ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5		 \
 ifeq ($(bind-now),yes)
 LDFLAGS.so += -Wl,-z,now
 endif
+LDFLAGS.so += -Wl,-z,unique
 
 modules.so := $(addsuffix .so, $(modules))
 
diff --git a/nptl/Makefile b/nptl/Makefile
index 584e0ffd96..8647a87da9 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -380,7 +380,7 @@ else
 tests-printers-libs := $(static-thread-library)
 endif
 
-LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst
+LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst,-z,unique
 
 # GCC-4.9 compiles 'sprintf(NULL, ...)' into UD2 on x86_64 without -fno-builtin
 CFLAGS-tst-cleanup2.c += -fno-builtin
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2020-03-30 17:45 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-03-30 17:43 [RFC][PATCH v4 00/15] Proof-of-Concept implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 01/15] Declare and describe the dlmopen RTLD_SHARED flag Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 02/15] include/link.h: Update the link_map struct to allow proxies Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 03/15] elf/dl-object.c: Implement a helper function to proxy link_map entries Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 04/15] elf/dl-load.c, elf-dl-open.c: Implement RTLD_SHARED dlmopen proxying Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 05/15] elf/dl-fini.c: Handle proxy link_map entries in the shutdown path Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 06/15] elf/dl-init.c: Skip proxied link map entries in the dl init path Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 07/15] Define a new DT_FLAGS_1 flag - DF_1_UNIQUE Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 08/15] Abstract the loaded-DSO search code into a private helper function Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 09/15] Compare loaded DSOs by file ID and check for DF_1_UNIQUE Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 10/15] Use the new DSO finder helper function since we have it Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 11/15] Use the DSO search helper to check for preloaded DF_1_UNIQUE DSOs Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 12/15] When loading new DSOs into alternate namespaces check for DF_1_UNIQUE Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 13/15] Suppress inter-namespace DSO sharing for audit libraries Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 14/15] dlsym, dlvsym should be able to look up symbols via DSO proxies Vivek Das Mohapatra via Libc-alpha
2020-03-30 17:43 ` [RFC][PATCH v4 15/15] Add the DT_FLAGS_1 DF_1_UNIQUE flag to the glibc cluster Vivek Das Mohapatra via Libc-alpha

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).