unofficial mirror of libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen
@ 2021-02-09 17:18 Vivek Das Mohapatra via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 01/20] Declare and describe the dlmopen RTLD_SHARED flag Vivek Das Mohapatra via Libc-alpha
                   ` (22 more replies)
  0 siblings, 23 replies; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: libc-alpha

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

Introduction:

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

  The following patchset provides 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 implements the following:

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

   - binutils patchset accepted upstream;
   - https://sourceware.org/git/?p=binutils-gdb.git
   - commit 8a87b2791181eb7fc1533ffaeb95df8d87d41493

 - LD_AUDIT paths will NOT apply this implict sharing rule:
   audit libraries will continue to be completely isolated.

 - The mechanism for tagging DSOs as implicitly shared has been changed
   from a DT_FLAGS_1 flag to a DT_VALRNGHI/LO range dynamic section tag.
   (Based on feedback on the binutils side of this patch series).

  - DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE

 - A flag RTLD_ISOLATE which is used inernally to suppress RTLD_SHARED
   behaviour when audit libraries are being loaded, and is also made available
   to users who really want a completely separate copy of glibc in their new
   namespace.

 - Tests for the new dlmopen behaviour

 - Adds the unique dso flag to htl/libpthread.so as well as nptl

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 (20):
  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
  elf/dl-open.c: Don't try libc linit in namespaces with no libc mapping
  elf/dl-open.c: when creating a proxy check the libc_map in NS 0
  Define a new dynamic section tag - DT_GNU_FLAGS_1
  Abstract the loaded-DSO search code into a private helper function
  Compare loaded DSOs by file ID and check for DF_GNU_1_UNIQUE
  Use the new DSO finder helper function since we have it
  Use the DSO search helper to check for preloaded DT_GNU_UNIQUE DSOs
  When loading DSOs into alternate namespaces check for DT_GNU_UNIQUE
  Suppress audit calls when a (new) namespace is empty
  Suppress inter-namespace DSO sharing for audit libraries
  dlsym, dlvsym should be able to look up symbols via DSO proxies
  Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  Add dlmopen / RTLD_SHARED tests
  Restore separate libc loading for the TLS/namespace storage test

 Makeconfig                           |    1 +
 Makerules                            |    2 +-
 bits/dlfcn.h                         |   10 +
 elf/Makefile                         |   97 ++-
 elf/dl-close.c                       |   43 +-
 elf/dl-fini.c                        |    6 +-
 elf/dl-init.c                        |    4 +-
 elf/dl-load.c                        |  227 +++++-
 elf/dl-object.c                      |   84 +++
 elf/dl-open.c                        |  109 ++-
 elf/dl-sym.c                         |   14 +
 elf/elf.h                            |    7 +-
 elf/get-dynamic-info.h               |   12 +
 elf/rtld.c                           |    2 +-
 elf/tst-dlmopen-auditmod.c           |   23 +
 elf/tst-dlmopen-common.h             |   33 +
 elf/tst-dlmopen-main.h               | 1022 ++++++++++++++++++++++++++
 elf/tst-dlmopen-modules.h            |   20 +
 elf/tst-dlmopen-rtld-audit-shared1.c |   11 +
 elf/tst-dlmopen-rtld-audit-shared2.c |   11 +
 elf/tst-dlmopen-rtld-audit-shared3.c |   11 +
 elf/tst-dlmopen-rtld-audit-shared4.c |   11 +
 elf/tst-dlmopen-rtld-audit-shared5.c |   11 +
 elf/tst-dlmopen-rtld-audit-shared6.c |   11 +
 elf/tst-dlmopen-rtld-audit-unique1.c |   11 +
 elf/tst-dlmopen-rtld-audit-unique2.c |   11 +
 elf/tst-dlmopen-rtld-audit-unique3.c |   11 +
 elf/tst-dlmopen-rtld-audit-unique4.c |   11 +
 elf/tst-dlmopen-rtld-audit-unique5.c |   11 +
 elf/tst-dlmopen-rtld-audit-unique6.c |   11 +
 elf/tst-dlmopen-rtld-shared1.c       |   11 +
 elf/tst-dlmopen-rtld-shared1.h       |   65 ++
 elf/tst-dlmopen-rtld-shared2.c       |   11 +
 elf/tst-dlmopen-rtld-shared2.h       |   67 ++
 elf/tst-dlmopen-rtld-shared3.c       |   11 +
 elf/tst-dlmopen-rtld-shared3.h       |   44 ++
 elf/tst-dlmopen-rtld-shared4.c       |   11 +
 elf/tst-dlmopen-rtld-shared4.h       |   15 +
 elf/tst-dlmopen-rtld-shared5.c       |   11 +
 elf/tst-dlmopen-rtld-shared5.h       |   26 +
 elf/tst-dlmopen-rtld-shared6.c       |   11 +
 elf/tst-dlmopen-rtld-shared6.h       |   37 +
 elf/tst-dlmopen-rtld-unique1.c       |   11 +
 elf/tst-dlmopen-rtld-unique1.h       |   87 +++
 elf/tst-dlmopen-rtld-unique2.c       |   11 +
 elf/tst-dlmopen-rtld-unique2.h       |   26 +
 elf/tst-dlmopen-rtld-unique3.c       |   11 +
 elf/tst-dlmopen-rtld-unique3.h       |   14 +
 elf/tst-dlmopen-rtld-unique4.c       |   11 +
 elf/tst-dlmopen-rtld-unique4.h       |   15 +
 elf/tst-dlmopen-rtld-unique5.c       |   11 +
 elf/tst-dlmopen-rtld-unique5.h       |   59 ++
 elf/tst-dlmopen-rtld-unique6.c       |   11 +
 elf/tst-dlmopen-rtld-unique6.h       |   52 ++
 elf/tst-dlmopen-sharedmod-norm.c     |   11 +
 elf/tst-dlmopen-sharedmod-uniq.c     |   11 +
 elf/tst-dlmopen-std-do-test.h        |   11 +
 elf/tst-tls-ie-dlmopen.c             |    4 +-
 htl/Makefile                         |    2 +-
 iconvdata/Makefile                   |    1 +
 include/elf.h                        |    2 +
 include/link.h                       |    7 +-
 nptl/Makefile                        |    2 +-
 sysdeps/generic/ldsodefs.h           |    9 +
 sysdeps/mips/bits/dlfcn.h            |   10 +
 65 files changed, 2494 insertions(+), 63 deletions(-)
 create mode 100644 elf/tst-dlmopen-auditmod.c
 create mode 100644 elf/tst-dlmopen-common.h
 create mode 100644 elf/tst-dlmopen-main.h
 create mode 100644 elf/tst-dlmopen-modules.h
 create mode 100644 elf/tst-dlmopen-rtld-audit-shared1.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-shared2.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-shared3.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-shared4.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-shared5.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-shared6.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-unique1.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-unique2.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-unique3.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-unique4.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-unique5.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-unique6.c
 create mode 100644 elf/tst-dlmopen-rtld-shared1.c
 create mode 100644 elf/tst-dlmopen-rtld-shared1.h
 create mode 100644 elf/tst-dlmopen-rtld-shared2.c
 create mode 100644 elf/tst-dlmopen-rtld-shared2.h
 create mode 100644 elf/tst-dlmopen-rtld-shared3.c
 create mode 100644 elf/tst-dlmopen-rtld-shared3.h
 create mode 100644 elf/tst-dlmopen-rtld-shared4.c
 create mode 100644 elf/tst-dlmopen-rtld-shared4.h
 create mode 100644 elf/tst-dlmopen-rtld-shared5.c
 create mode 100644 elf/tst-dlmopen-rtld-shared5.h
 create mode 100644 elf/tst-dlmopen-rtld-shared6.c
 create mode 100644 elf/tst-dlmopen-rtld-shared6.h
 create mode 100644 elf/tst-dlmopen-rtld-unique1.c
 create mode 100644 elf/tst-dlmopen-rtld-unique1.h
 create mode 100644 elf/tst-dlmopen-rtld-unique2.c
 create mode 100644 elf/tst-dlmopen-rtld-unique2.h
 create mode 100644 elf/tst-dlmopen-rtld-unique3.c
 create mode 100644 elf/tst-dlmopen-rtld-unique3.h
 create mode 100644 elf/tst-dlmopen-rtld-unique4.c
 create mode 100644 elf/tst-dlmopen-rtld-unique4.h
 create mode 100644 elf/tst-dlmopen-rtld-unique5.c
 create mode 100644 elf/tst-dlmopen-rtld-unique5.h
 create mode 100644 elf/tst-dlmopen-rtld-unique6.c
 create mode 100644 elf/tst-dlmopen-rtld-unique6.h
 create mode 100644 elf/tst-dlmopen-sharedmod-norm.c
 create mode 100644 elf/tst-dlmopen-sharedmod-uniq.c
 create mode 100644 elf/tst-dlmopen-std-do-test.h

-- 
2.20.1


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

* [RFC][PATCH v8 01/20] Declare and describe the dlmopen RTLD_SHARED flag
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-15 13:08   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 02/20] include/link.h: Update the link_map struct to allow proxies Vivek Das Mohapatra via Libc-alpha
                   ` (21 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: 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 f3bc63e958..0daa789693 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 5cec898de3..1331771a17 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.20.1


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

* [RFC][PATCH v8 02/20] include/link.h: Update the link_map struct to allow proxies
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 01/20] Declare and describe the dlmopen RTLD_SHARED flag Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-15 13:11   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 03/20] elf/dl-object.c: Implement a helper function to proxy link_map entries Vivek Das Mohapatra via Libc-alpha
                   ` (20 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: 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 4af16cb596..b51fa0cbdf 100644
--- a/include/link.h
+++ b/include/link.h
@@ -107,8 +107,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.  */
@@ -180,6 +181,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.20.1


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

* [RFC][PATCH v8 03/20] elf/dl-object.c: Implement a helper function to proxy link_map entries
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 01/20] Declare and describe the dlmopen RTLD_SHARED flag Vivek Das Mohapatra via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 02/20] include/link.h: Update the link_map struct to allow proxies Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-15 13:30   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 04/20] elf/dl-load.c, elf-dl-open.c: Implement RTLD_SHARED dlmopen proxying Vivek Das Mohapatra via Libc-alpha
                   ` (19 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: 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 1875599eb2..1a9d35c96b 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 9720a4e446..f58b4ac49f 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -974,6 +974,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;
 
 /* Restricted version of _dl_lookup_symbol_x.  Searches MAP (and only
    MAP) for the symbol UNDEF_NAME, with GNU hash NEW_HASH (computed
-- 
2.20.1


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

* [RFC][PATCH v8 04/20] elf/dl-load.c, elf-dl-open.c: Implement RTLD_SHARED dlmopen proxying
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (2 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 03/20] elf/dl-object.c: Implement a helper function to proxy link_map entries Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-15 14:53   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 05/20] elf/dl-fini.c: Handle proxy link_map entries in the shutdown path Vivek Das Mohapatra via Libc-alpha
                   ` (18 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: 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 | 60 +++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 104 insertions(+), 2 deletions(-)

diff --git a/elf/dl-load.c b/elf/dl-load.c
index 9e2089cfaa..3c5f667717 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -2006,6 +2006,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 *
@@ -2022,6 +2054,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 ab7aaa345e..4cb90bfe19 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -484,6 +484,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
@@ -508,6 +510,15 @@ dl_open_worker (void *a)
 	args->nsid = call_map->l_ns;
     }
 
+  /* Now that we know the NS for sure, sanity check the mode.  */
+  if (__glibc_likely(args->nsid == LM_ID_BASE) &&
+      __glibc_unlikely(mode & RTLD_SHARED))
+    {
+      args->mode &= ~RTLD_SHARED;
+      mode &= ~RTLD_SHARED;
+      want_proxy = 0;
+    }
+
   /* The namespace ID is now known.  Keep track of whether libc.so was
      already loaded, to determine whether it is necessary to call the
      early initialization routine (or clear libc_map on error).  */
@@ -541,6 +552,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))
     {
@@ -572,6 +601,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;
     }
 
@@ -787,10 +826,27 @@ 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;
+    }
+
   /* 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 *
-- 
2.20.1


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

* [RFC][PATCH v8 05/20] elf/dl-fini.c: Handle proxy link_map entries in the shutdown path
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (3 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 04/20] elf/dl-load.c, elf-dl-open.c: Implement RTLD_SHARED dlmopen proxying Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-15 17:08   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 06/20] elf/dl-init.c: Skip proxied link map entries in the dl init path Vivek Das Mohapatra via Libc-alpha
                   ` (17 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: 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 c51becd06b..a0432b884d 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 6dbdfe4b3e..10194488bb 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -73,7 +73,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);
 
@@ -111,7 +111,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.20.1


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

* [RFC][PATCH v8 06/20] elf/dl-init.c: Skip proxied link map entries in the dl init path
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (4 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 05/20] elf/dl-fini.c: Handle proxy link_map entries in the shutdown path Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-15 17:52   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 07/20] elf/dl-open.c: Don't try libc linit in namespaces with no libc mapping Vivek Das Mohapatra via Libc-alpha
                   ` (16 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: 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 b7e4b8a3af..a0183aa315 100644
--- a/elf/dl-init.c
+++ b/elf/dl-init.c
@@ -34,8 +34,8 @@ call_init (struct link_map *l, int argc, char **argv, char **env)
      need relocation, and neither do proxy objects.)  */
   assert (l->l_real->l_relocated || l->l_real->l_type == lt_executable);
 
-  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.20.1


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

* [RFC][PATCH v8 07/20] elf/dl-open.c: Don't try libc linit in namespaces with no libc mapping
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (5 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 06/20] elf/dl-init.c: Skip proxied link map entries in the dl init path Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-15 17:54   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 08/20] elf/dl-open.c: when creating a proxy check the libc_map in NS 0 Vivek Das Mohapatra via Libc-alpha
                   ` (15 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: libc-alpha

Secondary namespaces which share their libc mapping with the main
namespace cannot (and should not) have _dl_call_libc_early_init
called for them by dl_open_worker.
---
 elf/dl-open.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/elf/dl-open.c b/elf/dl-open.c
index 4cb90bfe19..dc4b386559 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -792,16 +792,21 @@ dl_open_worker (void *a)
      namespace.  */
   if (!args->libc_already_loaded)
     {
+      /* If this is a secondary (nsid != LM_ID_BASE) namespace then
+         it is POSSIBLE there's no libc_map at all - We use the one
+         shared with LM_ID_BASE instead (which MUST already be
+         initialised for us to even reach here).  */
       struct link_map *libc_map = GL(dl_ns)[args->nsid].libc_map;
 #ifdef SHARED
-      bool initial = libc_map->l_ns == LM_ID_BASE;
+      bool initial = libc_map && (libc_map->l_real->l_ns == LM_ID_BASE);
 #else
       /* In the static case, there is only one namespace, but it
 	 contains a secondary libc (the primary libc is statically
 	 linked).  */
       bool initial = false;
 #endif
-      _dl_call_libc_early_init (libc_map, initial);
+      if (libc_map != NULL)
+        _dl_call_libc_early_init (libc_map, initial);
     }
 
 #ifndef SHARED
-- 
2.20.1


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

* [RFC][PATCH v8 08/20] elf/dl-open.c: when creating a proxy check the libc_map in NS 0
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (6 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 07/20] elf/dl-open.c: Don't try libc linit in namespaces with no libc mapping Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-15 17:55   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 09/20] Define a new dynamic section tag - DT_GNU_FLAGS_1 Vivek Das Mohapatra via Libc-alpha
                   ` (14 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: libc-alpha

The libc_already_loaded check normally considers the libc_map entry
in GL(dl_ns)[args->nsid].libc_map.

This is not correct for proxies, which use the libc_map from
the default namespace (as proxies are dummy entries that point
to the base namespace via their l_real members).
---
 elf/dl-open.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/elf/dl-open.c b/elf/dl-open.c
index dc4b386559..096aa4c680 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -568,6 +568,7 @@ dl_open_worker (void *a)
     {
       proxy_ns = args->nsid;
       args->nsid = LM_ID_BASE;
+      args->libc_already_loaded = GL(dl_ns)[LM_ID_BASE].libc_map != NULL;
     }
 
   /* It was already open.  */
-- 
2.20.1


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

* [RFC][PATCH v8 09/20] Define a new dynamic section tag - DT_GNU_FLAGS_1
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (7 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 08/20] elf/dl-open.c: when creating a proxy check the libc_map in NS 0 Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-15 18:42   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 10/20] Abstract the loaded-DSO search code into a private helper function Vivek Das Mohapatra via Libc-alpha
                   ` (13 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: libc-alpha

Define a new flags section DT_GNU_FLAGS_1 (no more bits are available
in DT_GNU_FLAGS).

One flag is currently defined: DF_GNU_1_UNIQUE.

libc and its companion DSOs (libpthread et al) should have this
section and flag set.
---
 elf/elf.h              |  7 ++++++-
 elf/get-dynamic-info.h | 12 ++++++++++++
 include/elf.h          |  2 ++
 include/link.h         |  1 +
 4 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/elf/elf.h b/elf/elf.h
index 4f838d4af2..9f9b8e4291 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -895,6 +895,7 @@ typedef struct
    Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
    approach.  */
 #define DT_VALRNGLO	0x6ffffd00
+#define DT_GNU_FLAGS_1   0x6ffffdf4    /* Open DSO once across all namespaces */
 #define DT_GNU_PRELINKED 0x6ffffdf5	/* Prelinking timestamp */
 #define DT_GNU_CONFLICTSZ 0x6ffffdf6	/* Size of conflict section */
 #define DT_GNU_LIBLISTSZ 0x6ffffdf7	/* Size of library list */
@@ -909,7 +910,7 @@ typedef struct
 #define DT_SYMINENT	0x6ffffdff	/* Entry size of syminfo */
 #define DT_VALRNGHI	0x6ffffdff
 #define DT_VALTAGIDX(tag)	(DT_VALRNGHI - (tag))	/* Reverse order! */
-#define DT_VALNUM 12
+#define DT_VALNUM 13
 
 /* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
    Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
@@ -998,6 +999,10 @@ typedef struct
 #define	DF_1_WEAKFILTER 0x20000000
 #define	DF_1_NOCOMMON   0x40000000
 
+/* State flags selectable in the `d_un.d_val' element of the DT_GNU_FLAGS_1
+   entry in the dynamic section.  */
+#define DF_GNU_1_UNIQUE 0x00000001
+
 /* Flags for the feature selection in DT_FEATURE_1.  */
 #define DTF_1_PARINIT	0x00000001
 #define DTF_1_CONFEXP	0x00000002
diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
index d8ec32377d..d441b39576 100644
--- a/elf/get-dynamic-info.h
+++ b/elf/get-dynamic-info.h
@@ -175,6 +175,18 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
       if (l->l_flags_1 & DF_1_NOW)
 	info[DT_BIND_NOW] = info[VERSYMIDX (DT_FLAGS_1)];
     }
+  if (info[DT_VALTAGIDX (DT_GNU_FLAGS_1)
+           + DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM] != NULL)
+    {
+      l->l_gnu_flags_1 = info[DT_VALTAGIDX (DT_GNU_FLAGS_1)
+                              + DT_NUM + DT_THISPROCNUM
+                              + DT_VERSIONTAGNUM + DT_EXTRANUM]->d_un.d_val;
+
+      if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)
+	  && l->l_gnu_flags_1 & ~DT_GNU_1_SUPPORTED_MASK)
+	_dl_debug_printf ("\nWARNING: Unsupported flag value(s) of 0x%x in DT_GNU_FLAGS_1.\n",
+			  l->l_gnu_flags_1 & ~DT_GNU_1_SUPPORTED_MASK);
+    }
   if (info[DT_RUNPATH] != NULL)
     /* If both RUNPATH and RPATH are given, the latter is ignored.  */
     info[DT_RPATH] = NULL;
diff --git a/include/elf.h b/include/elf.h
index 14ed67ff67..5eee37c294 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -25,5 +25,7 @@
    (DF_1_NOW | DF_1_NODELETE | DF_1_INITFIRST | DF_1_NOOPEN \
     | DF_1_ORIGIN | DF_1_NODEFLIB | DF_1_PIE)
 
+#define DT_GNU_1_SUPPORTED_MASK DF_GNU_1_UNIQUE
+
 #endif /* !_ISOMAC */
 #endif /* elf.h */
diff --git a/include/link.h b/include/link.h
index b51fa0cbdf..55e0cad71d 100644
--- a/include/link.h
+++ b/include/link.h
@@ -285,6 +285,7 @@ struct link_map
     unsigned int l_used;
 
     /* Various flag words.  */
+    ElfW(Word) l_gnu_flags_1;
     ElfW(Word) l_feature_1;
     ElfW(Word) l_flags_1;
     ElfW(Word) l_flags;
-- 
2.20.1


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

* [RFC][PATCH v8 10/20] Abstract the loaded-DSO search code into a private helper function
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (8 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 09/20] Define a new dynamic section tag - DT_GNU_FLAGS_1 Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-15 19:25   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 11/20] Compare loaded DSOs by file ID and check for DF_GNU_1_UNIQUE Vivek Das Mohapatra via Libc-alpha
                   ` (12 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: 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 3c5f667717..2a01ab7ad2 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -2038,6 +2038,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 f58b4ac49f..d0b9a22779 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1242,6 +1242,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.20.1


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

* [RFC][PATCH v8 11/20] Compare loaded DSOs by file ID and check for DF_GNU_1_UNIQUE
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (9 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 10/20] Abstract the loaded-DSO search code into a private helper function Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-18 20:45   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 12/20] Use the new DSO finder helper function since we have it Vivek Das Mohapatra via Libc-alpha
                   ` (11 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: 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_GNU_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 2a01ab7ad2..780bca99e8 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1020,6 +1020,32 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
     }
 #endif
 
+  /* DSOs in the main namespace which are flagged DF_GNU_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_gnu_flags_1 & DF_GNU_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 096aa4c680..441b8b1330 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -561,6 +561,16 @@ dl_open_worker (void *a)
       return;
     }
 
+  /* If we are trying to load a DF_GNU_1_UNIQUE flagged DSO which was
+     NOT ALREADY LOADED (or not loaded with the name we are using) then
+     _dl_map_object will have returned 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.20.1


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

* [RFC][PATCH v8 12/20] Use the new DSO finder helper function since we have it
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (10 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 11/20] Compare loaded DSOs by file ID and check for DF_GNU_1_UNIQUE Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-19 14:39   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 13/20] Use the DSO search helper to check for preloaded DT_GNU_UNIQUE DSOs Vivek Das Mohapatra via Libc-alpha
                   ` (10 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: libc-alpha

---
 elf/dl-load.c | 43 +++++++++++++++++--------------------------
 1 file changed, 17 insertions(+), 26 deletions(-)

diff --git a/elf/dl-load.c b/elf/dl-load.c
index 780bca99e8..13ac2053b8 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -2133,35 +2133,26 @@ _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)
+  l = _dl_find_dso (name, nsid);
+
+  if (l != NULL)
     {
-      /* 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.  */
+#ifdef SHARED
+      /* If we are trying to load a DF_GNU_1_UNIQUE flagged DSO which WAS
+         already opened in the target NS but with RTLD_ISOLATE so it WAS NOT
+         created as a proxy we need to error out since we cannot satisfy the
+         DF_GNU_1_UNIQUE is-equivalent-to RTLD_SHARED semantics.  */
+      if (!(mode & RTLD_ISOLATE) &&
+          (l->l_ns != LM_ID_BASE) &&
+          (l->l_gnu_flags_1 & DF_GNU_1_UNIQUE) &&
+          !l->l_proxy)
+      {
+        _dl_signal_error (EEXIST, name, NULL,
+                          N_("object cannot be demoted to a proxy"));
+      }
+#endif
       return l;
     }
-
   /* Display information if we are debugging.  */
   if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)
       && loader != NULL)
-- 
2.20.1


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

* [RFC][PATCH v8 13/20] Use the DSO search helper to check for preloaded DT_GNU_UNIQUE DSOs
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (11 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 12/20] Use the new DSO finder helper function since we have it Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-19 17:26   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 14/20] When loading DSOs into alternate namespaces check for DT_GNU_UNIQUE Vivek Das Mohapatra via Libc-alpha
                   ` (9 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: libc-alpha

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-open.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/elf/dl-open.c b/elf/dl-open.c
index 441b8b1330..38b3587d4a 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -484,6 +484,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;
 
@@ -532,6 +533,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_FLAGS_1/DF_GNU_1_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_gnu_flags_1 & DF_GNU_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.20.1


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

* [RFC][PATCH v8 14/20] When loading DSOs into alternate namespaces check for DT_GNU_UNIQUE
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (12 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 13/20] Use the DSO search helper to check for preloaded DT_GNU_UNIQUE DSOs Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-19 18:11   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 15/20] Suppress audit calls when a (new) namespace is empty Vivek Das Mohapatra via Libc-alpha
                   ` (8 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: 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 DT_GNU_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 | 96 +++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 82 insertions(+), 14 deletions(-)

diff --git a/elf/dl-load.c b/elf/dl-load.c
index 13ac2053b8..13879af82c 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -837,6 +837,62 @@ _dl_init_paths (const char *llp, const char *source,
     __rtld_env_path_list.dirs = (void *) -1;
 }
 
+static ElfW(Word)
+_has_gnu_unique (int fd, const ElfW(Ehdr) *header, const ElfW(Phdr) *phdr)
+{
+  int unique = 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:
+          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_GNU_FLAGS_1:
+                  unique = entry.d_un.d_val & DF_GNU_1_UNIQUE;
+                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 unique;
+}
 
 /* Process PT_GNU_PROPERTY program header PH in module L after
    PT_LOAD segments are mapped.  Only one NT_GNU_PROPERTY_TYPE_0
@@ -1098,6 +1154,32 @@ _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 lose_errno;
+	}
+    }
+
+  /* We need to check for DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE before we start
+     initialising any namespace dependent metatada.  */
+  if (nsid != LM_ID_BASE)
+    {
+      /* 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 (_has_gnu_unique (fd, header, phdr))
+        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))
@@ -1115,20 +1197,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 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.20.1


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

* [RFC][PATCH v8 15/20] Suppress audit calls when a (new) namespace is empty
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (13 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 14/20] When loading DSOs into alternate namespaces check for DT_GNU_UNIQUE Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-19 19:45   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 16/20] Suppress inter-namespace DSO sharing for audit libraries Vivek Das Mohapatra via Libc-alpha
                   ` (7 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: libc-alpha

When preparing an RTLD_SHARED proxy in a new namespace
it is possible for the target namespace to be empty:

This can happen for RTLD_SHARED + LM_ID_NEWLM.

The audit infrastructure should not be invoked at this
point (as there's nothing there to audit yet).
---
 elf/dl-load.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/elf/dl-load.c b/elf/dl-load.c
index 13879af82c..4e8e7ca031 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1127,8 +1127,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
 	  && __glibc_unlikely (GLRO(dl_naudit) > 0))
 	{
 	  struct link_map *head = GL(dl_ns)[nsid]._ns_loaded;
-	  /* Do not call the functions for any auditing object.  */
-	  if (head->l_auditing == 0)
+	  /* Do not call the functions for any auditing object.
+	     Do not try to call auditing functions if the namespace
+	     is currently empty. This can hapen when opening the first
+	     DSO in a new namespace.  */
+	  if (head && head->l_auditing == 0)
 	    {
 	      struct audit_ifaces *afct = GLRO(dl_audit);
 	      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
-- 
2.20.1


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

* [RFC][PATCH v8 16/20] Suppress inter-namespace DSO sharing for audit libraries
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (14 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 15/20] Suppress audit calls when a (new) namespace is empty Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-19 20:39   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 17/20] dlsym, dlvsym should be able to look up symbols via DSO proxies Vivek Das Mohapatra via Libc-alpha
                   ` (6 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: libc-alpha

Audit libraries should not participate in DSO sharing: In
particular libraries tagged with DF_GNU_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 the RTLD_ISOLATE
flag from the relevant entry point in the dl modes argument.
---
 bits/dlfcn.h              |  3 +++
 elf/dl-load.c             |  5 +++--
 elf/dl-open.c             | 13 +++++++++++--
 elf/rtld.c                |  2 +-
 sysdeps/mips/bits/dlfcn.h |  3 +++
 5 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/bits/dlfcn.h b/bits/dlfcn.h
index 0daa789693..f910528b32 100644
--- a/bits/dlfcn.h
+++ b/bits/dlfcn.h
@@ -32,6 +32,9 @@
    visible as if the object were linked directly into the program.  */
 #define RTLD_GLOBAL	0x00100
 
+/* Suppress RTLD_SHARED and/or DF_GNU_1_UNIQUE.  */
+#define RTLD_ISOLATE 0x00040
+
 /* 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
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 4e8e7ca031..44fd3b5489 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1079,7 +1079,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
   /* DSOs in the main namespace which are flagged DF_GNU_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)
@@ -1174,7 +1174,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
 
   /* We need to check for DT_GNU_FLAGS_1/DF_GNU_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)))
     {
       /* 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
@@ -2188,6 +2188,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 38b3587d4a..d3c3e32be2 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -485,9 +485,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
@@ -539,6 +546,7 @@ dl_open_worker (void *a)
      mode and set 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);
@@ -650,7 +658,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 596b6ac3d9..82069658b3 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -659,7 +659,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/sysdeps/mips/bits/dlfcn.h b/sysdeps/mips/bits/dlfcn.h
index 1331771a17..a0a35bba5d 100644
--- a/sysdeps/mips/bits/dlfcn.h
+++ b/sysdeps/mips/bits/dlfcn.h
@@ -39,6 +39,9 @@
    share a single instance of a DSO.  */
 #define RTLD_SHARED 0x00020
 
+/* Suppress RTLD_SHARED and/or DF_GNU_1_UNIQUE.  */
+#define RTLD_ISOLATE 0x00040
+
 /* 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.20.1


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

* [RFC][PATCH v8 17/20] dlsym, dlvsym should be able to look up symbols via DSO proxies
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (15 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 16/20] Suppress inter-namespace DSO sharing for audit libraries Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-22 18:51   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs Vivek Das Mohapatra via Libc-alpha
                   ` (5 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: 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 dfd6169e12..b7252804ad 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -96,6 +96,10 @@ do_sym (void *handle, const char *name, void *who,
     {
       match = _dl_sym_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
@@ -140,6 +144,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;
 
@@ -150,6 +159,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.20.1


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

* [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (16 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 17/20] dlsym, dlvsym should be able to look up symbols via DSO proxies Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-22 20:39   ` Adhemerval Zanella via Libc-alpha
  2021-02-09 17:18 ` [RFC][PATCH v8 19/20] Add dlmopen / RTLD_SHARED tests Vivek Das Mohapatra via Libc-alpha
                   ` (4 subsequent siblings)
  22 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: libc-alpha

libc.so, libpthread.so etc should have the new unique-dso-by-default
flag set to allow dlmopen to work better (libc et al instance shared
by default when DSOs dlmopened into a new namespace).
---
 Makeconfig         | 1 +
 Makerules          | 2 +-
 htl/Makefile       | 2 +-
 iconvdata/Makefile | 1 +
 nptl/Makefile      | 2 +-
 5 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/Makeconfig b/Makeconfig
index 0a4811b5e5..d0e52f26fd 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 ca9885436e..82adffdc27 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/htl/Makefile b/htl/Makefile
index c15c1b194e..5d0d76d941 100644
--- a/htl/Makefile
+++ b/htl/Makefile
@@ -204,7 +204,7 @@ $(inst_libdir)/libpthread_syms.a: $(srcdir)/libpthread_syms.a $(+force)
 libc-link.so = $(common-objpfx)libc.so
 
 extra-B-pthread.so = -B$(common-objpfx)htl/
-LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst
+LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,unique,-z,nodelete,-z,initfirst
 
 include ../Rules
 
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index 55c527a5f7..ea5565eb40 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 8fb7fee6db..9090b88dec 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -349,7 +349,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,unique,-z,nodelete,-z,initfirst
 
 tests += tst-cancelx7 tst-cancelx17 tst-cleanupx4
 
-- 
2.20.1


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

* [RFC][PATCH v8 19/20] Add dlmopen / RTLD_SHARED tests
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (17 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-26 19:50   ` Adhemerval Zanella via Libc-alpha
  2021-02-26 20:26   ` Andreas Schwab
  2021-02-09 17:18 ` [RFC][PATCH v8 20/20] Restore separate libc loading for the TLS/namespace storage test Vivek Das Mohapatra via Libc-alpha
                   ` (3 subsequent siblings)
  22 siblings, 2 replies; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: libc-alpha

---
 elf/Makefile                         |   97 ++-
 elf/tst-dlmopen-auditmod.c           |   23 +
 elf/tst-dlmopen-common.h             |   33 +
 elf/tst-dlmopen-main.h               | 1022 ++++++++++++++++++++++++++
 elf/tst-dlmopen-modules.h            |   20 +
 elf/tst-dlmopen-rtld-audit-shared1.c |   11 +
 elf/tst-dlmopen-rtld-audit-shared2.c |   11 +
 elf/tst-dlmopen-rtld-audit-shared3.c |   11 +
 elf/tst-dlmopen-rtld-audit-shared4.c |   11 +
 elf/tst-dlmopen-rtld-audit-shared5.c |   11 +
 elf/tst-dlmopen-rtld-audit-shared6.c |   11 +
 elf/tst-dlmopen-rtld-audit-unique1.c |   11 +
 elf/tst-dlmopen-rtld-audit-unique2.c |   11 +
 elf/tst-dlmopen-rtld-audit-unique3.c |   11 +
 elf/tst-dlmopen-rtld-audit-unique4.c |   11 +
 elf/tst-dlmopen-rtld-audit-unique5.c |   11 +
 elf/tst-dlmopen-rtld-audit-unique6.c |   11 +
 elf/tst-dlmopen-rtld-shared1.c       |   11 +
 elf/tst-dlmopen-rtld-shared1.h       |   65 ++
 elf/tst-dlmopen-rtld-shared2.c       |   11 +
 elf/tst-dlmopen-rtld-shared2.h       |   67 ++
 elf/tst-dlmopen-rtld-shared3.c       |   11 +
 elf/tst-dlmopen-rtld-shared3.h       |   44 ++
 elf/tst-dlmopen-rtld-shared4.c       |   11 +
 elf/tst-dlmopen-rtld-shared4.h       |   15 +
 elf/tst-dlmopen-rtld-shared5.c       |   11 +
 elf/tst-dlmopen-rtld-shared5.h       |   26 +
 elf/tst-dlmopen-rtld-shared6.c       |   11 +
 elf/tst-dlmopen-rtld-shared6.h       |   37 +
 elf/tst-dlmopen-rtld-unique1.c       |   11 +
 elf/tst-dlmopen-rtld-unique1.h       |   87 +++
 elf/tst-dlmopen-rtld-unique2.c       |   11 +
 elf/tst-dlmopen-rtld-unique2.h       |   26 +
 elf/tst-dlmopen-rtld-unique3.c       |   11 +
 elf/tst-dlmopen-rtld-unique3.h       |   14 +
 elf/tst-dlmopen-rtld-unique4.c       |   11 +
 elf/tst-dlmopen-rtld-unique4.h       |   15 +
 elf/tst-dlmopen-rtld-unique5.c       |   11 +
 elf/tst-dlmopen-rtld-unique5.h       |   59 ++
 elf/tst-dlmopen-rtld-unique6.c       |   11 +
 elf/tst-dlmopen-rtld-unique6.h       |   52 ++
 elf/tst-dlmopen-sharedmod-norm.c     |   11 +
 elf/tst-dlmopen-sharedmod-uniq.c     |   11 +
 elf/tst-dlmopen-std-do-test.h        |   11 +
 44 files changed, 1998 insertions(+), 1 deletion(-)
 create mode 100644 elf/tst-dlmopen-auditmod.c
 create mode 100644 elf/tst-dlmopen-common.h
 create mode 100644 elf/tst-dlmopen-main.h
 create mode 100644 elf/tst-dlmopen-modules.h
 create mode 100644 elf/tst-dlmopen-rtld-audit-shared1.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-shared2.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-shared3.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-shared4.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-shared5.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-shared6.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-unique1.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-unique2.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-unique3.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-unique4.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-unique5.c
 create mode 100644 elf/tst-dlmopen-rtld-audit-unique6.c
 create mode 100644 elf/tst-dlmopen-rtld-shared1.c
 create mode 100644 elf/tst-dlmopen-rtld-shared1.h
 create mode 100644 elf/tst-dlmopen-rtld-shared2.c
 create mode 100644 elf/tst-dlmopen-rtld-shared2.h
 create mode 100644 elf/tst-dlmopen-rtld-shared3.c
 create mode 100644 elf/tst-dlmopen-rtld-shared3.h
 create mode 100644 elf/tst-dlmopen-rtld-shared4.c
 create mode 100644 elf/tst-dlmopen-rtld-shared4.h
 create mode 100644 elf/tst-dlmopen-rtld-shared5.c
 create mode 100644 elf/tst-dlmopen-rtld-shared5.h
 create mode 100644 elf/tst-dlmopen-rtld-shared6.c
 create mode 100644 elf/tst-dlmopen-rtld-shared6.h
 create mode 100644 elf/tst-dlmopen-rtld-unique1.c
 create mode 100644 elf/tst-dlmopen-rtld-unique1.h
 create mode 100644 elf/tst-dlmopen-rtld-unique2.c
 create mode 100644 elf/tst-dlmopen-rtld-unique2.h
 create mode 100644 elf/tst-dlmopen-rtld-unique3.c
 create mode 100644 elf/tst-dlmopen-rtld-unique3.h
 create mode 100644 elf/tst-dlmopen-rtld-unique4.c
 create mode 100644 elf/tst-dlmopen-rtld-unique4.h
 create mode 100644 elf/tst-dlmopen-rtld-unique5.c
 create mode 100644 elf/tst-dlmopen-rtld-unique5.h
 create mode 100644 elf/tst-dlmopen-rtld-unique6.c
 create mode 100644 elf/tst-dlmopen-rtld-unique6.h
 create mode 100644 elf/tst-dlmopen-sharedmod-norm.c
 create mode 100644 elf/tst-dlmopen-sharedmod-uniq.c
 create mode 100644 elf/tst-dlmopen-std-do-test.h

diff --git a/elf/Makefile b/elf/Makefile
index 16c89b6d07..bccf31b1a9 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -196,6 +196,38 @@ static-dlopen-environment = \
 tst-tls9-static-ENV = $(static-dlopen-environment)
 tst-single_threaded-static-dlopen-ENV = $(static-dlopen-environment)
 
+dlmopen-rtld-tests-norm := \
+	 tst-dlmopen-rtld-shared1 \
+	 tst-dlmopen-rtld-shared2 \
+	 tst-dlmopen-rtld-shared3 \
+	 tst-dlmopen-rtld-shared4 \
+	 tst-dlmopen-rtld-shared5 \
+	 tst-dlmopen-rtld-shared6
+
+dlmopen-rtld-tests-uniq := \
+	 tst-dlmopen-rtld-unique1 \
+	 tst-dlmopen-rtld-unique2 \
+	 tst-dlmopen-rtld-unique3 \
+	 tst-dlmopen-rtld-unique4 \
+	 tst-dlmopen-rtld-unique5 \
+	 tst-dlmopen-rtld-unique6
+
+dlmopen-rtld-audit-tests-norm := \
+	 tst-dlmopen-rtld-audit-shared1 \
+	 tst-dlmopen-rtld-audit-shared2 \
+	 tst-dlmopen-rtld-audit-shared3 \
+	 tst-dlmopen-rtld-audit-shared4 \
+	 tst-dlmopen-rtld-audit-shared5 \
+	 tst-dlmopen-rtld-audit-shared6
+
+dlmopen-rtld-audit-tests-uniq := \
+	 tst-dlmopen-rtld-audit-unique1 \
+	 tst-dlmopen-rtld-audit-unique2 \
+	 tst-dlmopen-rtld-audit-unique3 \
+	 tst-dlmopen-rtld-audit-unique4 \
+	 tst-dlmopen-rtld-audit-unique5 \
+	 tst-dlmopen-rtld-audit-unique6
+
 tests += restest1 preloadtest loadfail multiload origtest resolvfail \
 	 constload1 order noload filter \
 	 reldep reldep2 reldep3 reldep4 nodelete nodelete2 \
@@ -225,7 +257,11 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
 	 tst-audit14 tst-audit15 tst-audit16 \
 	 tst-single_threaded tst-single_threaded-pthread \
 	 tst-tls-ie tst-tls-ie-dlmopen argv0test \
-	 tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask
+	 tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \
+	 $(dlmopen-rtld-tests-norm) \
+	 $(dlmopen-rtld-tests-uniq) \
+	 $(dlmopen-rtld-audit-tests-norm) \
+	 $(dlmopen-rtld-audit-tests-uniq)
 #	 reldep9
 tests-internal += loadtest unload unload2 circleload1 \
 	 neededtest neededtest2 neededtest3 neededtest4 \
@@ -286,6 +322,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		$(modules-execstack-$(have-z-execstack)) \
 		tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 \
 		tst-dlmopen1mod tst-auditmod1 \
+		tst-dlmopen-sharedmod-norm \
+		tst-dlmopen-sharedmod-uniq \
+		tst-dlmopen-auditmod \
 		unload3mod1 unload3mod2 unload3mod3 unload3mod4 \
 		unload4mod1 unload4mod2 unload4mod3 unload4mod4 \
 		unload6mod1 unload6mod2 unload6mod3 \
@@ -325,6 +364,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		tst-tlsalign-lib tst-nodelete-opened-lib tst-nodelete2mod \
 		tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \
 		tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \
+		tst-dlmopen-auditmod \
 		tst-latepthreadmod $(tst-tls-many-dynamic-modules) \
 		tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \
 		tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \
@@ -823,6 +863,9 @@ tst-nodelete-uniquemod.so-no-z-defs = yes
 tst-nodelete-rtldmod.so-no-z-defs = yes
 tst-nodelete-zmod.so-no-z-defs = yes
 tst-nodelete2mod.so-no-z-defs = yes
+tst-dlmopen-sharedmod-norm.so-no-z-defs = yes
+tst-dlmopen-sharedmod-uniq.so-no-z-defs = yes
+tst-dlmopen-auditmod.so-no-z-defs = yes
 
 ifeq ($(build-shared),yes)
 # Build all the modules even when not actually running test programs.
@@ -1301,6 +1344,58 @@ $(objpfx)tst-dlmopen2.out: $(objpfx)tst-dlmopen1mod.so
 $(objpfx)tst-dlmopen3: $(libdl)
 $(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
 
+LDFLAGS-tst-dlmopen-sharedmod-uniq.so = -Wl,-z,unique
+$(objpfx)tst-dlmopen-sharedmod-norm.so: $(libdl)
+$(objpfx)tst-dlmopen-sharedmod-uniq.so: $(libdl)
+$(objpfx)tst-dlmopen-auditmod.so: $(libdl)
+
+dlmopen-rtld-tests-norm-executables := \
+	 $(foreach x,$(dlmopen-rtld-tests-norm),$(objpfx)$(x))
+dlmopen-rtld-tests-norm-out := \
+	 $(foreach x,$(dlmopen-rtld-tests-norm),$(objpfx)$(x).out)
+
+dlmopen-rtld-tests-uniq-executables := \
+	 $(foreach x,$(dlmopen-rtld-tests-uniq),$(objpfx)$(x))
+dlmopen-rtld-tests-uniq-out := \
+	 $(foreach x,$(dlmopen-rtld-tests-uniq),$(objpfx)$(x).out)
+
+dlmopen-rtld-audit-tests-norm-executables := \
+	 $(foreach x,$(dlmopen-rtld-audit-tests-norm),$(objpfx)$(x))
+dlmopen-rtld-audit-tests-norm-out := \
+	 $(foreach x,$(dlmopen-rtld-audit-tests-norm),$(objpfx)$(x).out)
+
+dlmopen-rtld-audit-tests-uniq-executables := \
+	 $(foreach x,$(dlmopen-rtld-audit-tests-uniq),$(objpfx)$(x))
+dlmopen-rtld-audit-tests-uniq-out := \
+	 $(foreach x,$(dlmopen-rtld-audit-tests-uniq),$(objpfx)$(x).out)
+
+$(dlmopen-rtld-tests-norm-executables): $(libdl)
+$(dlmopen-rtld-tests-norm-out): $(objpfx)tst-dlmopen-sharedmod-norm.so
+
+$(dlmopen-rtld-tests-uniq-executables): $(libdl)
+$(dlmopen-rtld-tests-uniq-out): $(objpfx)tst-dlmopen-sharedmod-uniq.so
+
+
+$(dlmopen-rtld-audit-tests-norm-executables): $(libdl)
+$(dlmopen-rtld-audit-tests-norm-out): $(objpfx)tst-dlmopen-sharedmod-norm.so
+$(dlmopen-rtld-audit-tests-norm-out): $(objpfx)tst-dlmopen-auditmod.so
+tst-dlmopen-rtld-audit-shared1-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
+tst-dlmopen-rtld-audit-shared2-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
+tst-dlmopen-rtld-audit-shared3-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
+tst-dlmopen-rtld-audit-shared4-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
+tst-dlmopen-rtld-audit-shared5-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
+tst-dlmopen-rtld-audit-shared6-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
+
+$(dlmopen-rtld-audit-tests-uniq-executables): $(libdl)
+$(dlmopen-rtld-audit-tests-uniq-out): $(objpfx)tst-dlmopen-sharedmod-uniq.so
+$(dlmopen-rtld-audit-tests-uniq-out): $(objpfx)tst-dlmopen-auditmod.so
+tst-dlmopen-rtld-audit-unique1-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
+tst-dlmopen-rtld-audit-unique2-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
+tst-dlmopen-rtld-audit-unique3-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
+tst-dlmopen-rtld-audit-unique4-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
+tst-dlmopen-rtld-audit-unique5-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
+tst-dlmopen-rtld-audit-unique6-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
+
 $(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so
 tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
 
diff --git a/elf/tst-dlmopen-auditmod.c b/elf/tst-dlmopen-auditmod.c
new file mode 100644
index 0000000000..04457249d0
--- /dev/null
+++ b/elf/tst-dlmopen-auditmod.c
@@ -0,0 +1,23 @@
+/* Audit module for tst-dlmopen-rtld-audit-*
+   Copyright © 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+unsigned int
+la_version (unsigned int version)
+{
+  return version;
+}
diff --git a/elf/tst-dlmopen-common.h b/elf/tst-dlmopen-common.h
new file mode 100644
index 0000000000..5653c9c02c
--- /dev/null
+++ b/elf/tst-dlmopen-common.h
@@ -0,0 +1,33 @@
+#pragma once
+
+/* Common infrastructure for tst-dlmopen-rtld-*
+   Copyright © 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <gnu/lib-names.h>
+
+typedef struct
+{
+  const char *name;
+  void *free;
+} dlmopen_testresult;
+
+typedef dlmopen_testresult * (*dlmopen_testfunc) (void);
+
diff --git a/elf/tst-dlmopen-main.h b/elf/tst-dlmopen-main.h
new file mode 100644
index 0000000000..2e091e9b8d
--- /dev/null
+++ b/elf/tst-dlmopen-main.h
@@ -0,0 +1,1022 @@
+#pragma once
+
+/* Main infrastructure for tst-dlmopen-rtld-*
+   Copyright © 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/* dlmopen ± RTLD_SHARED/RTLD_ISOLATE semantics:
+
+   RTLD_ISOLATE's purpose is to suppress all shared behaviour,
+   mainly used fir LD_AUDIT code paths but available to the user
+   and also useful for constructing test case preconditions.
+
+   dlmopen should have the following behaviour:
+
+   Notation:
+        Number of namespace (+ = make a new one in an empty NS)
+        |
+     [+]X[p] - p indicates a proxy
+      |
+      + → new enry after the dlmopen call
+
+      Need to be able to inspect:
+
+      list of dl handles before we start (base state)
+      list of dl handles after an action in each namespace
+      ns of a given dl handle
+      _real_ ns of a given handle (ie where does a proxy point)
+
+      Target is a normal DSO:
+      Before | Target NS | RTLD Flags | After  | handle NS | libc NS
+      =======+===========+============+========+===========+=========
+      dlmopen-rtld-shared1:
+      -------+-----------+------------+--------+-----------+---------
+       -     | 0         | -          | +0     | 0         | 0
+       0     | 0         | -          | 0      | 0         | 0
+       0     | 0         | SHARED     | 0      | 0         | 0
+       0     | +         | -          | 0,+1   | 1         | 0
+       0,1   | 0         | -          | 0,1    | 0         | 0
+       0,1   | 0         | SHARED     | 0,1    | 0         | 0
+      =======+===========+============+========+===========+=========
+      dlmopen-rtld-shared2:
+      -------+-----------+------------+--------+-----------+---------
+       -     | 0         | SHARED     | +0     | 0         | 0
+       0     | +         | SHARED     | 0,+1p  | 1p        | 0
+       0,1p  | 0         | -          | 0,1p   | 0         | 0
+       0,1p  | 0         | SHARED     | 0,1p   | 0         | 0
+       0,1p  | 1         | -          | 0,1p   | 1p        | 0
+       0,1p  | 1         | SHARED     | 0,1p   | 1p        | 0
+      =======+===========+============+========+===========+=========
+      dlmopen-rtld-shared3
+      -------+-----------+------------+--------+-----------+---------
+       -     | +         | -          | +1     | 1         | 0
+       1     | 0         | -          | +0,1   | 0         | 0
+       0,1   | 1         | -          | 0,1    | 1         | 0
+       0,1   | 1         | SHARED     | 0,1    | ERR       | -
+      =======+===========+============+========+===========+=========
+      dlmopen-rtld-shared4
+      -------+-----------+------------+--------+-----------+---------
+       -     | +         | SHARED     | +0,+1p | 1p        | 0
+      =======+===========+============+========+===========+=========
+      dlmopen-rtld-shared5
+      -------+-----------+------------+--------+-----------+---------
+       1     | 0         | SHARED     | +0,1   | 0         | 0
+      =======+===========+============+========+===========+=========
+      dlmopen-rtld-shared6
+      -------+-----------+------------+--------+-----------+---------
+       1     | 1         | -          | 1      | 0         | 0
+       1     | 1         | SHARED     | 1      | ERR       | -
+
+      Target is a DF_GNU_1_UNIQUE DSO:
+      Before | Target NS | RTLD Flags | After  | handle NS | libc NS
+      =======+===========+============+========+===========+=========
+      dlmopen-rtld-unique1:
+      -------+-----------+------------+--------+-----------+---------
+       -     | 0         | -          | +0     | 0         | 0
+       0     | 0         | -          | 0      | 0         | 0
+       0     | 0         | SHARED     | 0      | 0         | 0
+       0     | +         | -          | 0,+1p  | 1p        | 0
+       0,1p  | 0         | -          | 0,1p   | 0         | 0
+       0,1p  | 0         | SHARED     | 0,1p   | 0         | 0
+       0,1p  | 1         | -          | 0,1p   | 1p        | 0
+       0,1p  | 1         | SHARED     | 0,1p   | 1p        | 0
+      =======+===========+============+========+===========+=========
+      dlmopen-rtld-unique2:
+      -------+-----------+------------+--------+-----------+---------
+       -     | 0         | SHARED     | +0     | 0         | 0
+       0     | +         | SHARED     | 0,+1p  | 1p        | 0
+      =======+===========+============+========+===========+=========
+      dlmopen-rtld-unique3:
+      -------+-----------+------------+--------+-----------+---------
+       -     | +         | -          | +0,+1p | 1p        | 0
+      =======+===========+============+========+===========+=========
+      dlmopen-rtld-unique4:
+      -------+-----------+------------+--------+-----------+---------
+       -     | +         | SHARED     | +0,+1p | 1p        | 0
+      =======+===========+============+========+===========+=========
+      dlmopen-rtld-unique5:
+      -------+-----------+------------+--------+-----------+---------
+       -     | +         | ISOLATE    | +1     | 1         | 1
+       1     | 0         | -          | +0,1   | 0         | 0
+       0,1   | 0         | -          | 0,1    | 0         | 0
+       0,1   | 0         | SHARED     | 0,1    | 0         | 0
+       0,1   | 1         | -          | 0,1    | ERR       | -
+      =======+===========+============+========+===========+=========
+      dlmopen-rtld-unique6:
+      -------+-----------+------------+--------+-----------+---------
+       -     | +1        | ISOLATE    | +1     | 1         | 1
+       1     | 1         | -          | 1      | ERR       | -
+       1     | 1         | SHARED     | 1      | ERR       | -
+       1     | 0         | SHARED     | +0,1   | 0         | 0
+       0,1   | 1         | SHARED     | 0,1    | ERR       | -
+*/
+
+#include "tst-dlmopen-common.h"
+#include <dl-dtprocnum.h>
+#include <link.h>
+
+#define DSO_NORMAL "$ORIGIN/tst-dlmopen-sharedmod-norm.so"
+#define DSO_UNIQUE "$ORIGIN/tst-dlmopen-sharedmod-uniq.so"
+#define DSO_TESTFN "rtld_shared_testfunc"
+#define DSO_NAMESTUB "tst-dlmopen-sharedmod-"
+#define MAX_NS 16
+
+#define END_TESTS { .name = NULL },
+
+#define ERROR(test, fmt, ...) \
+  ({ if (last_test != test)                                        \
+       printf ("FAILED: %s (%s):\n", test->name, test->desc);      \
+     printf ("%s @ %d - " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \
+     last_test = test; })
+
+static void *last_test;
+
+typedef enum
+  {
+   NONE  = 0,
+   DSO   = 1,
+   PROXY = 2,
+   NEW   = 4,
+  } dso_type;
+
+typedef struct
+{
+  const char *name;
+  const char *desc;
+  int is_prep_stage;
+  const char *dso_name;
+  int failure;
+
+  struct
+  {
+    const char *dso_path;
+    Lmid_t ns;
+    int flags;
+  } args;
+
+  dso_type preloaded[MAX_NS];
+  dso_type loaded[MAX_NS];
+  dso_type handle_type;
+  Lmid_t handle_ns;
+  Lmid_t free_ns;
+} dlmopen_test_spec;
+
+struct r_scope_elem
+{
+  struct tst_lm **r_list;
+  unsigned int r_nlist;
+};
+
+/* This is a copy of the first part of the internal definition of
+   struct link_map from <include/link.h>.  We use it to check some
+   expected internal state that's not readily accessible via public APIs.
+ */
+struct tst_lm
+  {
+    /* These first few members are part of the protocol with the debugger.
+       This is the same format used in SVR4.  */
+
+    ElfW(Addr) l_addr;		/* Difference between the address in the ELF
+                                   file and the addresses in memory.  */
+    char *l_name;		/* Absolute file name object was found in.  */
+    ElfW(Dyn) *l_ld;		/* Dynamic section of the shared object.  */
+    struct tst_lm *l_next, *l_prev; /* Chain of loaded objects.  */
+
+    /* All following members are internal to the dynamic linker.
+       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 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 tst_lm *l_real;
+
+    /* Number of the namespace this link map belongs to.  */
+    Lmid_t l_ns;
+
+    struct libname_list *l_libname;
+    /* Indexed pointers to dynamic section.
+       [0,DT_NUM) are indexed by the processor-independent tags.
+       [DT_NUM,DT_NUM+DT_THISPROCNUM) are indexed by the tag minus DT_LOPROC.
+       [DT_NUM+DT_THISPROCNUM,DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM) are
+       indexed by DT_VERSIONTAGIDX(tagvalue).
+       [DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM,
+        DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM) are indexed by
+       DT_EXTRATAGIDX(tagvalue).
+       [DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM,
+        DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM) are
+       indexed by DT_VALTAGIDX(tagvalue) and
+       [DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM,
+        DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM+DT_ADDRNUM)
+       are indexed by DT_ADDRTAGIDX(tagvalue), see <elf.h>.  */
+
+    ElfW(Dyn) *l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM
+                      + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
+    const ElfW(Phdr) *l_phdr;	/* Pointer to program header table in core.  */
+    ElfW(Addr) l_entry;		/* Entry point location.  */
+    ElfW(Half) l_phnum;		/* Number of program header entries.  */
+    ElfW(Half) l_ldnum;		/* Number of dynamic segment entries.  */
+
+    /* Array of DT_NEEDED dependencies and their dependencies, in
+       dependency order for symbol lookup (with and without
+       duplicates).  There is no entry before the dependencies have
+       been loaded.  */
+    struct r_scope_elem l_searchlist;
+
+    /* We need a special searchlist to process objects marked with
+       DT_SYMBOLIC.  */
+    struct r_scope_elem l_symbolic_searchlist;
+
+    /* Dependent object that first caused this object to be loaded.  */
+    struct link_map *l_loader;
+
+    /* Array with version names.  */
+    struct r_found_version *l_versions;
+    unsigned int l_nversions;
+
+    /* Symbol hash table.  */
+    Elf_Symndx l_nbuckets;
+    Elf32_Word l_gnu_bitmask_idxbits;
+    Elf32_Word l_gnu_shift;
+    const ElfW(Addr) *l_gnu_bitmask;
+    union
+    {
+      const Elf32_Word *l_gnu_buckets;
+      const Elf_Symndx *l_chain;
+    };
+    union
+    {
+      const Elf32_Word *l_gnu_chain_zero;
+      const Elf_Symndx *l_buckets;
+    };
+
+    unsigned int l_direct_opencount; /* Reference count for dlopen/dlclose.  */
+    enum			/* Where this object came from.  */
+      {
+        lt_executable,		/* The main executable program.  */
+        lt_library,		/* Library needed by main executable.  */
+        lt_loaded		/* Extra run-time loaded shared object.  */
+      } l_type:2;
+    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.  */
+    unsigned int l_soname_added:1; /* Nonzero if the SONAME is for sure in
+                                      the l_libname list.  */
+    unsigned int l_faked:1;	/* Nonzero if this is a faked descriptor
+                                   without associated file.  */
+    unsigned int l_need_tls_init:1; /* Nonzero if GL(dl_init_static_tls)
+                                       should be called on this link map
+                                       when relocation finishes.  */
+    unsigned int l_auditing:1;	/* Nonzero if the DSO is used in auditing.  */
+    unsigned int l_audit_any_plt:1; /* Nonzero if at least one audit module
+                                       is interested in the PLT interception.*/
+    unsigned int l_removed:1;	/* Nozero if the object cannot be used anymore
+                                   since it is removed.  */
+    unsigned int l_contiguous:1; /* Nonzero if inter-segment holes are
+                                    mprotected or if no holes are present at
+                                    all.  */
+    unsigned int l_symbolic_in_local_scope:1; /* Nonzero if l_local_scope
+                                                 during LD_TRACE_PRELINKING=1
+                                                 contains any DT_SYMBOLIC
+                                                 libraries.  */
+    unsigned int l_free_initfini:1; /* Nonzero if l_initfini can be
+                                       freed, ie. not allocated with
+                                       the dummy malloc in ld.so.  */
+  };
+
+typedef struct { void *handle; Lmid_t ns; } test_handle;
+static test_handle cached_handles[32];
+
+static void
+cache_test_handle (void *handle, Lmid_t ns)
+{
+  int i;
+
+  for (i = 0; i < sizeof(cached_handles)/sizeof(test_handle); i++)
+    if (cached_handles[i].handle == NULL)
+      {
+        cached_handles[i].handle = handle;
+        cached_handles[i].ns = ns;
+        break;
+      }
+}
+
+__attribute__((unused))
+static struct tst_lm *
+link_map_of_dl_handle (void *handle)
+{
+  struct tst_lm *lm = NULL;
+
+  if (dlinfo (handle, RTLD_DI_LINKMAP, &lm) == 0)
+    return lm;
+
+  printf ("dlinfo (LINKMAP) for %s in %s failed: %s\n",
+          LIBC_SO, __func__, dlerror ());
+
+  return NULL;
+}
+
+__attribute__((unused))
+static Lmid_t
+ns_of_dl_handle (void *handle)
+{
+  Lmid_t ns = 0;
+
+  if (dlinfo (handle, RTLD_DI_LMID, &ns) == 0)
+    return ns;
+
+  printf ("dlinfo (LMID) for %s in %s failed: %s\n",
+          LIBC_SO, __func__, dlerror ());
+
+  return -1;
+}
+
+__attribute__((unused))
+static Lmid_t real_ns_of_dl_handle (void *handle)
+{
+  Lmid_t ns = 0;
+  struct tst_lm *lm = link_map_of_dl_handle (handle);
+
+  if (lm == NULL)
+    return -1;
+
+  // printf ("DEBUG: handle %p; LM %p; proxy: %d / %p\n",
+  // handle, lm, lm->l_proxy, lm->l_real);
+
+  if (lm->l_proxy)
+    {
+      // printf ("DEBUG: proxy %p vs real %p\n", lm, lm->l_real);
+      ns = ns_of_dl_handle ((void *) lm->l_real);
+    }
+  else
+    ns = ns_of_dl_handle (handle);
+
+  return ns;
+}
+
+__attribute__((unused))
+static const char *str_soname (const char *name)
+{
+  char *slash = NULL;
+
+  if (name == NULL)
+    return NULL;
+
+  if ((slash = strrchr (name, '/')))
+    return ++slash;
+  else
+    return name;
+}
+
+__attribute__((unused))
+static const char *lm_name (struct tst_lm *lm)
+{
+  if (lm)
+    return lm->l_name;
+
+  return NULL;
+}
+
+
+static int dlm_dso_is_loaded (void *handle)
+{
+  if (handle != RTLD_DEFAULT)
+    {
+#ifdef DEBUG_DSO_LOADCHECK
+      Dl_info sinfo = {};
+#endif
+
+      if (((struct tst_lm *) handle)->l_type != lt_loaded)
+        return 0;
+
+#ifdef DEBUG_DSO_LOADCHECK
+      printf ("checking %p %s for %s\n",
+              handle, ((struct tst_lm *)handle)->l_name, DSO_TESTFN);
+#endif
+
+      void *symbol = dlsym (handle, DSO_TESTFN);
+
+#ifdef DEBUG_DSO_LOADCHECK
+      dladdr (symbol, &sinfo);
+      printf ("  -> %s (in %s (%p))\n",
+              sinfo.dli_fname,
+              sinfo.dli_sname,
+              sinfo.dli_saddr);
+#endif
+
+      return symbol ? 1 : 0;
+    }
+
+  for (int i = 0; i < sizeof(cached_handles)/sizeof(test_handle); i++)
+    {
+      if (cached_handles[i].handle == NULL)
+        break;
+
+      if (((struct tst_lm *) cached_handles[i].handle)->l_type != lt_loaded)
+        continue;
+
+#ifdef DEBUG_DSO_LOADCHECK
+      printf ("checking %p %s for %s\n",
+              cached_handles[i].handle,
+              ((struct tst_lm *)cached_handles[i].handle)->l_name,
+              DSO_TESTFN);
+#endif
+
+      if (dlsym (cached_handles[i].handle, DSO_TESTFN) != NULL)
+        return 1;
+    }
+
+  return 0;
+}
+
+static int call_testfunc (dlmopen_test_spec *test, void *handle)
+{
+  Dl_info dli = {};
+  struct tst_lm *lm = NULL;
+  dlmopen_testfunc func = NULL;
+  dlmopen_testresult *result = NULL;
+
+  if (handle != RTLD_DEFAULT)
+    func = dlsym (handle, DSO_TESTFN);
+
+  if (func == NULL)
+    {
+      ERROR (test, "test function %s not found\n", DSO_TESTFN);
+      return 0;
+    }
+
+  result = (func)();
+
+  if (result == NULL)
+    {
+      ERROR (test, "test function %s returned NULL\n", DSO_TESTFN);
+      return 0;
+    }
+
+  dladdr1 (result->free, &dli, (void **)&lm, RTLD_DL_LINKMAP);
+
+  if (lm == NULL)
+    {
+      ERROR (test, "free() implementation from test module is invalid\n");
+      return 0;
+    }
+
+  if (lm->l_ns != test->free_ns)
+    {
+      ERROR (test,
+             "free() function from test module was from ns %d, expected %d\n",
+             (int)lm->l_ns, (int)test->free_ns);
+      return 0;
+    }
+
+  printf ("%s: %s: %s in ns %d using free() from ns %d: OK\n",
+          test->name, test->args.dso_path, DSO_TESTFN,
+          (int)test->handle_ns, (int)lm->l_ns);
+
+  return 1;
+}
+
+static void *link_map_snapshot_array (void *handle, void *func, Lmid_t ns, size_t *len)
+{
+  struct tst_lm *lm = NULL;
+  struct tst_lm *start = NULL;
+
+  if (len)
+    *len = 0;
+
+  if (handle != NULL)
+    {
+      dlinfo (handle, RTLD_DI_LINKMAP, &lm);
+    }
+  else if (func != NULL)
+    {
+      Dl_info dli = {};
+
+      dladdr1 (func, &dli, (void **)&lm, RTLD_DL_LINKMAP);
+    }
+  else if (ns >= LM_ID_BASE)
+    {
+      for (int i = 0; i < sizeof(cached_handles)/sizeof(test_handle); i++)
+        {
+          if (cached_handles[i].handle == NULL)
+            break;
+
+          if (cached_handles[i].ns != ns)
+            continue;
+
+          dlinfo (cached_handles[i].handle, RTLD_DI_LINKMAP, &lm);
+          break;
+        }
+    }
+
+  if (lm == NULL)
+    return NULL;
+
+  start = lm;
+
+  while (start->l_prev)
+    start = start->l_prev;
+
+  size_t lm_size = 0;
+
+  for (lm = start; lm; lm = lm->l_next)
+    lm_size++;
+
+  struct tst_lm **lm_list = calloc (lm_size + 1, sizeof (struct tst_lm *));
+
+  if (len)
+    *len = lm_size;
+
+  int i = 0;
+
+  for (lm = start; lm; lm = lm->l_next)
+    lm_list[i++] = lm;
+  lm_list[i] = NULL;
+
+  return lm_list;
+}
+
+__attribute__((unused))
+static int search_link_map_array (struct tst_lm **lma, size_t len, void *handle)
+{
+  if (lma == NULL)
+    return 0;
+
+  if (len == 0)
+    return 0;
+  
+  struct tst_lm *target = link_map_of_dl_handle (handle);
+
+  for (int i = 0; i < len; i++)
+    {
+      //printf ("searching for %p in <%p>[%d] == %p\n",
+      //        handle, lma, i, lma[i]);
+      if (handle == (struct tst_lm *)(lma[i]))
+        return 1;
+
+      if (target->l_proxy)
+        if (target->l_real == (struct tst_lm *)(lma[i]))
+          return 1;
+    }
+
+  return 0;
+}
+
+#ifdef DEBUG_DSO_SEARCH
+#define TRACE2(fmt, ...) \
+  printf ("  find-test-dso (%s @ %d): " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
+#else
+#define TRACE2(fmt, ...) 
+#endif
+
+static struct tst_lm *
+find_test_dso_in_link_map_array (struct tst_lm **lma, size_t len)
+{
+  if (lma == NULL)
+    return NULL;
+
+  if (len == 0)
+    return NULL;
+
+  for (int i = 0; i < len; i++)
+    {
+      if (!lma[i] || !lma[i]->l_name)
+        continue;
+
+      TRACE2 ("%p [%d/%d] %s", lma, i, (int)len - 1,
+              lma[i] ? (lma[i]->l_name ?: "???.so") : "NULL" );
+
+      if (lma[i] && lma[i]->l_name)
+        if (strstr (lma[i]->l_name, DSO_NAMESTUB))
+          if (dlsym (lma[i], DSO_TESTFN) != NULL)
+            return (struct tst_lm *)lma[i];
+    }
+  
+  return NULL;
+}
+
+__attribute__((unused))
+static void *link_map_list (void *handle, void *func, int *len, Lmid_t *ns)
+{
+  struct tst_lm *lm = NULL;
+  struct tst_lm *start = NULL;
+
+  if (len)
+    *len = 0;
+
+  if (handle != NULL)
+    {
+      dlinfo (handle, RTLD_DI_LINKMAP, &lm);
+    }
+  else if (func != NULL)
+    {
+      Dl_info dli = {};
+
+      dladdr1 (func, &dli, (void **)&lm, RTLD_DL_LINKMAP);
+    }
+
+  if (lm == NULL)
+    return NULL;
+
+  if (ns)
+    *ns = lm->l_ns;
+
+  // rewind to start of link map list:
+  start = lm;
+
+  while (start->l_prev)
+    start = start->l_prev;
+
+  size_t lm_size = 0;
+
+  for (lm = start; lm; lm = lm->l_next)
+    lm_size++;
+
+  if (len)
+    *len = lm_size;
+
+  return start;
+}
+
+#ifdef DEBUG_DLMOPEN_TEST_WRAPPER
+#define TRACE(fmt, ...) \
+  printf ("%s (%s @ %d): " fmt "\n", test->name, __FILE__, __LINE__, ##__VA_ARGS__)
+#else
+#define TRACE(fmt, ...)
+#endif
+
+static int process_test_spec (dlmopen_test_spec *test)
+{
+  void *handle = NULL;
+  size_t lm_before_len[MAX_NS] = { 0 };
+  size_t lm_after_len[MAX_NS] = { 0 };
+  struct tst_lm **lm_before[MAX_NS] = { NULL };
+  struct tst_lm **lm_after[MAX_NS] = { NULL };
+  struct tst_lm *preloads[MAX_NS] = { NULL };
+  int want_preload = 0;
+  int test_status = 0;
+
+  memset (&lm_after[0], 0, sizeof (lm_after));
+  memset (&lm_before[0], 0, sizeof (lm_before));
+  memset (&preloads[0], 0, sizeof (preloads));
+
+  TRACE("LD_AUDIT = %s", getenv("LD_AUDIT") ?: "-");
+  TRACE("BEFORE SNAPSHOTS: %p", &lm_before[0]);
+  TRACE("AFTER  SNAPSHOTS: %p", &lm_after[0]);
+  TRACE("preloads        : %p", preloads);
+  TRACE("setup done");
+  
+  if (test->args.dso_path && *test->args.dso_path && !test->dso_name)
+    test->dso_name = str_soname (test->args.dso_path);
+
+  TRACE("DSO short name: %s", test->dso_name);
+  
+  // get the existing link map contents before the test runs:
+  lm_before[0] = link_map_snapshot_array (NULL, process_test_spec,
+                                          LM_ID_BASE, &lm_before_len[0]);
+  for (int i = 1; i < MAX_NS; i++)
+    lm_before[i] = link_map_snapshot_array (NULL, NULL, i, &lm_before_len[i]);
+
+  TRACE("link map snapshots cached");
+  
+  for (int i = 0; i < MAX_NS; i++)
+    {
+      if (test->preloaded[i] & PROXY)
+        {
+          struct tst_lm **lm = lm_before[i];
+          want_preload++;
+
+          if (lm != NULL)
+            for (int j = 0; !preloads[i] && (j < lm_before_len[i]); j++)
+              if (dlm_dso_is_loaded (lm[j]) && lm[j]->l_proxy)
+                preloads[i] = lm[j];
+
+          if (!preloads[i])
+            {
+              ERROR (test,
+                     "needed proxy for %s preloaded in NS %d, not found\n",
+                     test->dso_name, i);
+              goto cleanup;
+            }
+        }
+      else if (test->preloaded[i] & DSO)
+        {
+          struct tst_lm **lm = lm_before[i];
+          int lm_max = lm_before_len[i];
+          want_preload++;
+
+          if (lm != NULL)
+            for (int j = 0; !preloads[i] && (j < lm_max); j++)
+              {
+                if (dlm_dso_is_loaded (lm[j]) && !lm[j]->l_proxy)
+                  preloads[i] = lm[j];
+              }
+          if (!preloads[i])
+            {
+              ERROR (test,
+                     "needed %s preloaded in NS %d, not found\n",
+                     test->dso_name, i);
+              goto cleanup;
+            }
+        }
+    }
+  TRACE("preload checks (A)");
+  
+  if (dlm_dso_is_loaded (RTLD_DEFAULT))
+    {
+      // test DSO module must _not_ be preloaded, and is:
+      if (!want_preload)
+        {
+          ERROR (test, "DSO %s unexpectedly loaded before test\n", test->dso_name);
+          goto cleanup;
+        }
+    }
+  else
+    {
+      // DSO is not loaded, and must be:
+      // In theory we can never see this error as it
+      // should be caught by the preceding preload loop:
+      if (want_preload)
+        {
+          ERROR (test, "DSO %s must be preloaded (and is not)\n", test->args.dso_path);
+          goto cleanup;
+        }
+    }
+  TRACE("preload checks (B) %s", test->name);
+
+  if (!(test->args.flags & (RTLD_NOW|RTLD_LAZY)))
+    test->args.flags |= RTLD_NOW;
+
+  handle = dlmopen (test->args.ns, test->args.dso_path, test->args.flags);
+  TRACE("dlmopen returned %p", handle);
+
+  if (handle == NULL)
+    {
+      const char *status = "failed";
+
+      if (test->failure)
+        {
+          status = "failed (EXPECTED)";
+          test_status = 1;
+
+          printf ("%s: dlmopen(%s, %d, 0x%0x) failed: OK\n",
+                  test->name, test->args.dso_path,
+                  (int)test->args.ns, (int)test->args.flags);
+          printf ("Returned: %p\n\n", handle);
+
+          goto cleanup;
+        }
+
+      ERROR (test, "");
+
+      if (test->is_prep_stage)
+        printf ("(during setup of preconditions): ");
+      else
+        printf (": ");
+
+      if (test->args.ns == LM_ID_BASE)
+        printf ("dlmopen (LM_ID_BASE, \"%s\", 0x%x) %s: %s\n",
+                test->args.dso_path, test->args.flags, status, dlerror ());
+      else
+        printf ("dlmopen (%d, \"%s\", 0x%x) %s: %s\n",
+                (int)test->args.ns, test->args.dso_path, test->args.flags, status, dlerror ());
+
+      goto cleanup;
+    }
+  else if (test->failure)
+    {
+      ERROR (test, "dlmopen() call should have failed, but did not\n");
+      goto cleanup;
+    }
+
+  TRACE("return status checked");
+
+  if (!dlm_dso_is_loaded (handle))
+    {
+      ERROR (test, "DSO %s (%p) missing function (%s)\n",
+             test->args.dso_path, handle, DSO_TESTFN);
+      goto cleanup;
+    }
+
+  TRACE ("loaded DSO sanity checked");
+
+  Lmid_t hns = ns_of_dl_handle (handle);
+  Lmid_t real_hns = real_ns_of_dl_handle (handle);
+  Lmid_t proxy_ns = 0;
+
+  call_testfunc (test, handle);
+  TRACE (DSO_TESTFN "called");
+
+  cache_test_handle (handle, hns);
+  TRACE ("handle %p cached (ns %d)", handle, (int)hns);
+
+  // if the real ns was different to the apparent one
+  // then we have a proxy and we need to shuffle the values,
+  // else leave the proxy ns as 0 as an expect.proxy_ns of 0
+  // means we weren't expecting a proxy:
+  if (real_hns != hns)
+    {
+      proxy_ns = hns;
+      hns = real_hns;
+    }
+
+  if (proxy_ns)
+    printf ("Returned: proxy ns:%d (real ns: %d)\n\n", (int)proxy_ns, (int)hns);
+  else
+    printf ("Returned: dso ns:%d\n\n", (int)hns);
+
+  Lmid_t expected;
+  if (test->handle_type & PROXY)
+    expected = proxy_ns;
+  else
+    expected = hns;
+
+  TRACE("check expected ns %d", (int)expected);
+
+  if (test->args.ns == LM_ID_NEWLM)
+    {
+      if (expected <= LM_ID_BASE)
+        {
+          ERROR (test, "DSO should have been in NS > %d, was in %d\n",
+                 LM_ID_BASE, (int)expected);
+          goto cleanup;
+        }
+
+      // for any cases where we can't predict
+      // the namespace in advance:
+      if (test->handle_ns == LM_ID_NEWLM)
+        test->handle_ns = expected;
+    }
+  else
+    {
+      if (test->args.ns != expected)
+        {
+          ERROR (test, "DSO should have been in NS %d, was in %d\n",
+                 (int)test->args.ns, (int)expected);
+          goto cleanup;
+        }
+    }
+
+  TRACE("ns %d Ok", (int)expected);
+
+  if (test->handle_type & PROXY) // expecting a proxy
+    {
+      if (proxy_ns != 0) // got a proxy
+        {
+          if (test->handle_ns != proxy_ns) // but not in the right place
+            {
+              ERROR (test, "DSO proxy should have been in ns %d, was in %d\n",
+                     (int)test->handle_ns, (int)proxy_ns);
+              goto cleanup;
+            }
+        }
+      else // didn't get a proxy
+        {
+          ERROR (test,
+                 "DSO should have been a proxy in ns %d,"
+                 " was a non-proxy in ns %d\n",
+                 (int)test->handle_ns, (int)hns);
+          goto cleanup;
+        }
+    }
+  else // not expecting a proxy
+    {
+      if (proxy_ns > 0)
+        {
+          ERROR (test,
+                 "DSO should NOT have been a proxy,"
+                 " was a proxy in ns %d (real ns %d)\n",
+                 (int)proxy_ns, (int)hns);
+          goto cleanup;
+        }
+
+      if (test->handle_ns != hns)
+        {
+          ERROR (test,
+                 "DSO should have been in ns %d,"
+                 " was in ns %d\n",
+                 (int)test->handle_ns, (int)hns);
+          goto cleanup;
+        }
+    }
+  TRACE ("proxy status Ok");
+
+  // get the new link map contents after the test has run:
+  lm_after[0] = link_map_snapshot_array (NULL, process_test_spec,
+                                         LM_ID_BASE, &lm_after_len[0]);
+  for (int i = 1; i < MAX_NS; i++)
+    lm_after[i] = link_map_snapshot_array (NULL, NULL, i, &lm_after_len[i]);
+
+  for (int i = 0; i < MAX_NS; i++)
+    {
+      TRACE("checking status of NS %d", i);
+      void *old_handle =
+        find_test_dso_in_link_map_array (lm_before[i], lm_before_len[i]);
+      TRACE ("old handle is %p", old_handle);
+
+      void *new_handle =
+        find_test_dso_in_link_map_array (lm_after[i], lm_after_len[i]);
+      TRACE ("new handle is %p", new_handle);
+
+      if (test->loaded[i] == NONE)
+        {
+          TRACE ("ns %d requirement is NONE", i);
+          if (old_handle != NULL)
+            {
+              ERROR (test,
+                     "Unexpected preload DSO %s in ns %d\n",
+                     lm_name (old_handle), i);
+              goto cleanup;
+            }
+          if (new_handle != NULL)
+            {
+              ERROR (test, "Unexpected new DSO %s in ns %d\n",
+                     lm_name (new_handle), i);
+              goto cleanup;
+            }
+          continue;
+        }
+
+      if (test->loaded[i] & NEW)
+        {
+          TRACE("ns %d requirement is NEW", i);
+          if (old_handle != NULL)
+            {
+              ERROR (test,
+                     "DSO in ns %d should have been a new load,"
+                     " found to have been preloaded\n", i);
+              goto cleanup;
+            }
+          if (new_handle == NULL)
+            {
+              ERROR (test, "Expected DSO in ns %d, not found\n", i);
+              goto cleanup;
+            }
+        }
+      else
+        {
+          TRACE("ns %d requirement is OLD", i);
+          if (new_handle == NULL)
+            {
+              ERROR (test, "Expected new DSO in ns %d, not found\n", i);
+              goto cleanup;
+            }
+
+          if (old_handle != new_handle)
+            {
+              ERROR (test, "DSO in ns %d changed. This should be impossible, "
+                     "sanity check the test code in %s\n", i, __FILE__);
+              goto cleanup;
+            }
+        }
+
+      if (test->loaded[i] & PROXY)
+        {
+          TRACE ("rechecking DSO status in ns %d", i);
+          if (!((struct tst_lm *)new_handle)->l_proxy)
+            {
+              ERROR (test, "DSO in ns %d should be a proxy but is not\n", i);
+              goto cleanup;
+            }
+        }
+      else
+        {
+          TRACE ("rechecking proxy status in ns %d", i);
+          if (((struct tst_lm *)new_handle)->l_proxy)
+            {
+              ERROR (test, "DSO in ns %d should NOT be a proxy but is\n", i);
+              goto cleanup;
+            }
+        }
+    }
+
+  test_status = 1;
+
+ cleanup:
+  for (int i = 0; i < MAX_NS; i++)
+     free (lm_after[i]);
+  for (int i = 0; i < MAX_NS; i++)
+    free (lm_before[i]);
+
+  return test_status;
+}
+
+
diff --git a/elf/tst-dlmopen-modules.h b/elf/tst-dlmopen-modules.h
new file mode 100644
index 0000000000..4bbf431ec3
--- /dev/null
+++ b/elf/tst-dlmopen-modules.h
@@ -0,0 +1,20 @@
+#pragma once
+/* Module-specific infrastructure for tst-dlmopen-rtld-*
+   Copyright © 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include "tst-dlmopen-common.h"
diff --git a/elf/tst-dlmopen-rtld-audit-shared1.c b/elf/tst-dlmopen-rtld-audit-shared1.c
new file mode 100644
index 0000000000..1e9f604327
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-audit-shared1.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 2
+#include "tst-dlmopen-rtld-shared1.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-audit-shared2.c b/elf/tst-dlmopen-rtld-audit-shared2.c
new file mode 100644
index 0000000000..53064dd345
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-audit-shared2.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 2
+#include "tst-dlmopen-rtld-shared2.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-audit-shared3.c b/elf/tst-dlmopen-rtld-audit-shared3.c
new file mode 100644
index 0000000000..de90bc1258
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-audit-shared3.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 2
+#include "tst-dlmopen-rtld-shared3.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-audit-shared4.c b/elf/tst-dlmopen-rtld-audit-shared4.c
new file mode 100644
index 0000000000..c600b2f4dc
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-audit-shared4.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 2
+#include "tst-dlmopen-rtld-shared4.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-audit-shared5.c b/elf/tst-dlmopen-rtld-audit-shared5.c
new file mode 100644
index 0000000000..cd223d041b
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-audit-shared5.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 2
+#include "tst-dlmopen-rtld-shared5.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-audit-shared6.c b/elf/tst-dlmopen-rtld-audit-shared6.c
new file mode 100644
index 0000000000..f84303b1b4
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-audit-shared6.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 2
+#include "tst-dlmopen-rtld-shared6.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-audit-unique1.c b/elf/tst-dlmopen-rtld-audit-unique1.c
new file mode 100644
index 0000000000..f60b9c05d4
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-audit-unique1.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 2
+#include "tst-dlmopen-rtld-unique1.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-audit-unique2.c b/elf/tst-dlmopen-rtld-audit-unique2.c
new file mode 100644
index 0000000000..199b1d3606
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-audit-unique2.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 2
+#include "tst-dlmopen-rtld-unique2.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-audit-unique3.c b/elf/tst-dlmopen-rtld-audit-unique3.c
new file mode 100644
index 0000000000..f3ebe58828
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-audit-unique3.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 2
+#include "tst-dlmopen-rtld-unique3.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-audit-unique4.c b/elf/tst-dlmopen-rtld-audit-unique4.c
new file mode 100644
index 0000000000..ef555672d2
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-audit-unique4.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 2
+#include "tst-dlmopen-rtld-unique4.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-audit-unique5.c b/elf/tst-dlmopen-rtld-audit-unique5.c
new file mode 100644
index 0000000000..b7faa5d02c
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-audit-unique5.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 2
+#include "tst-dlmopen-rtld-unique5.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-audit-unique6.c b/elf/tst-dlmopen-rtld-audit-unique6.c
new file mode 100644
index 0000000000..d431e3a787
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-audit-unique6.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 2
+#include "tst-dlmopen-rtld-unique6.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-shared1.c b/elf/tst-dlmopen-rtld-shared1.c
new file mode 100644
index 0000000000..812d21e692
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-shared1.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 1
+#include "tst-dlmopen-rtld-shared1.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-shared1.h b/elf/tst-dlmopen-rtld-shared1.h
new file mode 100644
index 0000000000..bd733cb3c4
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-shared1.h
@@ -0,0 +1,65 @@
+static dlmopen_test_spec dltest[] =
+  {
+   {
+    .name = "dlmopen:0:none--ns0",
+    .desc = "dlmopen as dlopen",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_BASE,
+    .loaded = { [0] = DSO|NEW },
+    .handle_type = DSO,
+    .handle_ns = LM_ID_BASE,
+   },
+   {
+    .name = "dlmopen:0:ns0--ns0",
+    .desc = "dlmopen a preloaded DSO in the base NS",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_BASE,
+    .preloaded = { [0] = DSO },
+    .loaded = { [0] = DSO },
+    .handle_type = DSO,
+    .handle_ns = LM_ID_BASE,
+   },
+   {
+    .name = "dlmopen-shared:0:ns0--ns0",
+    .desc = "dlmopen a preloaded DSO in the base NS with RTLD_SHARED",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_BASE,
+    .args.flags = RTLD_SHARED,
+    .preloaded = { [0] = DSO },
+    .loaded = { [0] = DSO },
+    .handle_type = DSO,
+    .handle_ns = LM_ID_BASE,
+   },
+   {
+    .name = "dlmopen:0:ns0--nsX",
+    .desc = "dlmopen a preloaded DSO in the base NS into a new NS",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_NEWLM,
+    .preloaded = { [0] = DSO },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO|NEW },
+    .handle_type = DSO,
+    .handle_ns = EXPECTED_NS,
+   },
+   {
+    .name = "dlmopen:0:ns0-nsX--ns0-nsX",
+    .desc = "dlmopen a preloaded DSO in the base & secondary NS into the base NS",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_BASE,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+    .handle_type = DSO,
+    .handle_ns = LM_ID_BASE,
+   },
+   {
+    .name = "dlmopen-shared:0:ns0-nsX--ns0-nsX",
+    .desc = "dlmopen a preloaded DSO in the base & secondary NS into the base NS",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_BASE,
+    .args.flags = RTLD_SHARED,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+    .handle_type = DSO,
+    .handle_ns = LM_ID_BASE,
+   },
+   END_TESTS
+  };
diff --git a/elf/tst-dlmopen-rtld-shared2.c b/elf/tst-dlmopen-rtld-shared2.c
new file mode 100644
index 0000000000..f830832a0a
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-shared2.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 1
+#include "tst-dlmopen-rtld-shared2.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-shared2.h b/elf/tst-dlmopen-rtld-shared2.h
new file mode 100644
index 0000000000..9775619b9a
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-shared2.h
@@ -0,0 +1,67 @@
+static dlmopen_test_spec dltest[] =
+  {
+   {
+    .name = "dlmopen-shared:0:none--ns0",
+    .desc = "dlmopen as dlopen with RTLD_SHARED",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_BASE,
+    .args.flags  = RTLD_SHARED,
+    .loaded = { [0] = DSO|NEW },
+    .handle_ns = LM_ID_BASE,
+    .handle_type = DSO,
+   },
+   {
+    .name = "dlmopen-shared:X:ns0--ns0-nsXp",
+    .desc = "dlmopen into a new namespace with the target already in the base NS",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_NEWLM,
+    .args.flags = RTLD_SHARED,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = PROXY,
+    .preloaded = { [0] = DSO },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY|NEW }
+   },
+   {
+    .name = "dlmopen:0:ns0-nsXp--ns0-nsXp",
+    .desc = "dlmopen into base NS while proxy already in nsX",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_BASE,
+    .handle_ns = 0,
+    .handle_type = DSO,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+   },
+   {
+    .name = "dlmopen-shared:0:ns0-nsXp--ns0-nsXp",
+    .desc = "dlmopen with RTLD_SHARED into base NS while proxy already in nsX",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_BASE,
+    .args.flags = RTLD_SHARED,
+    .handle_ns = 0,
+    .handle_type = DSO,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+   },
+   {
+    .name = "dlmopen:X:ns0-nsXp--ns0-nsXp",
+    .desc = "dlmopen into NS X while proxy already in nsX",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = EXPECTED_NS,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = PROXY,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+   },
+   {
+    .name = "dlmopen-shared:X:ns0-nsXp--ns0-nsXp",
+    .desc = "dlmopen with RTLD_SHARED into NS X while proxy already in nsX",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = EXPECTED_NS,
+    .args.flags = RTLD_SHARED,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = PROXY,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+   },
+   END_TESTS
+  };
diff --git a/elf/tst-dlmopen-rtld-shared3.c b/elf/tst-dlmopen-rtld-shared3.c
new file mode 100644
index 0000000000..a63753eb84
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-shared3.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 1
+#include "tst-dlmopen-rtld-shared3.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-shared3.h b/elf/tst-dlmopen-rtld-shared3.h
new file mode 100644
index 0000000000..23fce58bae
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-shared3.h
@@ -0,0 +1,44 @@
+static dlmopen_test_spec dltest[] =
+  {
+   {
+    .name = "dlmopen:X:none--nsX",
+    .desc = "dlmopen into nsX, no copies preloaded",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_NEWLM,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = DSO,
+    .preloaded = { },
+    .loaded = { [EXPECTED_NS] = DSO|NEW },
+   },
+   {
+    .name = "dlmopen:0:nsX--ns0-nsX",
+    .desc = "dlmopen into ns 0, copy already loaded in ns X",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_BASE,
+    .handle_ns = 0,
+    .handle_type = DSO,
+    .preloaded = { [EXPECTED_NS] = DSO },
+    .loaded = { [0] = DSO|NEW, [EXPECTED_NS] = DSO },
+   },
+   {
+    .name = "dlmopen:X:ns0-nsX--nsX",
+    .desc = "dlmopen into ns X, copies already in ns 0 and ns X",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = EXPECTED_NS,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = DSO,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+   },
+   {
+    .name = "dlmopen-shared:X:ns0-nsX--nsX",
+    .desc = "dlmopen RTLD_SHARED into nsX with a DSO already in NS0 and NSX",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = EXPECTED_NS,
+    .args.flags = RTLD_SHARED,
+    .failure = 1,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+   },
+   END_TESTS
+  };
diff --git a/elf/tst-dlmopen-rtld-shared4.c b/elf/tst-dlmopen-rtld-shared4.c
new file mode 100644
index 0000000000..7c3d92e37b
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-shared4.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 1
+#include "tst-dlmopen-rtld-shared4.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-shared4.h b/elf/tst-dlmopen-rtld-shared4.h
new file mode 100644
index 0000000000..9ad29b9a6d
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-shared4.h
@@ -0,0 +1,15 @@
+static dlmopen_test_spec dltest[] =
+  {
+   {
+    .name = "dlmopen-shared:X:none--ns0-nsX",
+    .desc = "dlmopen a new proxy in nsX with no preexisting dso in ns0",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_NEWLM,
+    .args.flags = RTLD_SHARED,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = PROXY,
+    .preloaded = { },
+    .loaded = { [0] = DSO|NEW, [EXPECTED_NS] = PROXY|NEW },
+   },
+   END_TESTS
+  };
diff --git a/elf/tst-dlmopen-rtld-shared5.c b/elf/tst-dlmopen-rtld-shared5.c
new file mode 100644
index 0000000000..f59d14e7b6
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-shared5.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 1
+#include "tst-dlmopen-rtld-shared5.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-shared5.h b/elf/tst-dlmopen-rtld-shared5.h
new file mode 100644
index 0000000000..220129a5cf
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-shared5.h
@@ -0,0 +1,26 @@
+static dlmopen_test_spec dltest[] =
+  {
+   {
+    .name = "dlmopen-preload:X:none--nsX",
+    .desc = "preload a DSO into ns1 to prepare for other tests",
+    .is_prep_stage = 1,
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_NEWLM,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = DSO,
+    .preloaded = { },
+    .loaded = { [EXPECTED_NS] = DSO|NEW },
+   },
+   {
+    .name = "dlmopen-shared:0:nsX--nsX-ns0",
+    .desc = "dlmopen RTLD_SHARED into ns0 when preloaded into nsX",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_BASE,
+    .args.flags = RTLD_SHARED,
+    .handle_ns = 0,
+    .handle_type = DSO,
+    .preloaded = { [EXPECTED_NS] = DSO },
+    .loaded = { [0] = DSO|NEW, [EXPECTED_NS] = DSO },
+   },
+   END_TESTS
+  };
diff --git a/elf/tst-dlmopen-rtld-shared6.c b/elf/tst-dlmopen-rtld-shared6.c
new file mode 100644
index 0000000000..469fb3566d
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-shared6.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 1
+#include "tst-dlmopen-rtld-shared6.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-shared6.h b/elf/tst-dlmopen-rtld-shared6.h
new file mode 100644
index 0000000000..116e53ea51
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-shared6.h
@@ -0,0 +1,37 @@
+static dlmopen_test_spec dltest[] =
+  {
+   {
+    .name = "dlmopen-preload:X:none--nsX",
+    .desc = "preload a DSO into nsX to prepare for other tests",
+    .is_prep_stage = 1,
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = LM_ID_NEWLM,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = DSO,
+    .preloaded = { },
+    .loaded = { [EXPECTED_NS] = DSO|NEW },
+   },
+   {
+    .name = "dlmopen:X:nsX--nsX",
+    .desc = "dlmopen a dso in nsX while already loaded there",
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = EXPECTED_NS,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = DSO,
+    .preloaded = { [EXPECTED_NS] = DSO },
+    .loaded = { [EXPECTED_NS] = DSO },
+   },
+   {
+    .name = "dlmopen-shared:X:nsX--nsX",
+    .desc = "dlmopen RTLD_SHARED a dso in nsX while already loaded there",
+    .failure = 1,
+    .args.dso_path = DSO_NORMAL,
+    .args.ns = EXPECTED_NS,
+    .args.flags = RTLD_SHARED,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = DSO,
+    .preloaded = { [EXPECTED_NS] = DSO },
+    .loaded = { [EXPECTED_NS] = DSO },
+   },
+   END_TESTS
+  };
diff --git a/elf/tst-dlmopen-rtld-unique1.c b/elf/tst-dlmopen-rtld-unique1.c
new file mode 100644
index 0000000000..867345582f
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-unique1.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 1
+#include "tst-dlmopen-rtld-unique1.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-unique1.h b/elf/tst-dlmopen-rtld-unique1.h
new file mode 100644
index 0000000000..f7d32959c2
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-unique1.h
@@ -0,0 +1,87 @@
+static dlmopen_test_spec dltest[] =
+  {
+   {
+    .name = "dlmopen-unique:0:none--ns0",
+    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into ns0",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_BASE,
+    .handle_ns = 0,
+    .handle_type = DSO,
+    .preloaded = { },
+    .loaded = { [0] = DSO|NEW },
+   },
+   {
+    .name = "dlmopen-unique:0:ns0--ns0",
+    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into ns0 while already present",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_BASE,
+    .handle_ns = 0,
+    .handle_type = DSO,
+    .preloaded = { [0] = DSO },
+    .loaded = { [0] = DSO },
+   },
+   {
+    .name = "dlmopen-unique-shared:0:ns0--ns0",
+    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso into ns0 while already present",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_BASE,
+    .args.flags = RTLD_SHARED,
+    .handle_ns = 0,
+    .handle_type = DSO,
+    .preloaded = { [0] = DSO },
+    .loaded = { [0] = DSO },
+   },
+   {
+    .name = "dlmopen-unique:X:ns0--nsX",
+    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into nsX while present in ns0",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_NEWLM,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = PROXY,
+    .preloaded = { [0] = DSO },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY|NEW },
+   },
+   {
+    .name = "dlmopen-unique:0:ns0-nsXp--ns0--nsXp",
+    .desc = "dlmopen a DF_GNU_1_UNIQUE dso already in ns0 proxied in nsX",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_BASE,
+    .handle_ns = 0,
+    .handle_type = DSO,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+   },
+   {
+    .name = "dlmopen-shared-unique:0:ns0-nsXp--ns0-nsXp",
+    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso into ns0 already in ns0 and proxied in nsX",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_BASE,
+    .args.flags = RTLD_SHARED,
+    .handle_ns = 0,
+    .handle_type = DSO,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+   },
+   {
+    .name = "dlmopen-unique:0:ns0-nsXp--ns0-nsXp",
+    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into ns0 already in ns0 and proxied in nsX",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = EXPECTED_NS,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = PROXY,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+   },
+   {
+    .name = "dlmopen-unique:0:ns0-nsXp--ns0-nsXp",
+    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso into ns0 already in ns0 and proxied in nsX",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = EXPECTED_NS,
+    .args.flags = RTLD_SHARED,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = PROXY,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
+   },
+   END_TESTS
+  };
diff --git a/elf/tst-dlmopen-rtld-unique2.c b/elf/tst-dlmopen-rtld-unique2.c
new file mode 100644
index 0000000000..dabb87b43f
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-unique2.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 1
+#include "tst-dlmopen-rtld-unique2.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-unique2.h b/elf/tst-dlmopen-rtld-unique2.h
new file mode 100644
index 0000000000..911e0180ab
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-unique2.h
@@ -0,0 +1,26 @@
+static dlmopen_test_spec dltest[] =
+  {
+   {
+    .name = "dlmopen-shared-unique:0:none--ns0",
+    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso in the base ns",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_BASE,
+    .args.flags = RTLD_SHARED,
+    .handle_ns = 0,
+    .handle_type = DSO,
+    .preloaded = { },
+    .loaded = { [0] = DSO|NEW },
+   },
+   {
+    .name = "dlmopen-shared-unique:1:ns0--ns0-ns1p",
+    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso into ns1 while present in ns0",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_NEWLM,
+    .args.flags = RTLD_SHARED,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = PROXY,
+    .preloaded = { [0] = DSO },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY|NEW },
+   },
+   END_TESTS
+  };
diff --git a/elf/tst-dlmopen-rtld-unique3.c b/elf/tst-dlmopen-rtld-unique3.c
new file mode 100644
index 0000000000..db8a567a3f
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-unique3.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 1
+#include "tst-dlmopen-rtld-unique3.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-unique3.h b/elf/tst-dlmopen-rtld-unique3.h
new file mode 100644
index 0000000000..b400bad07f
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-unique3.h
@@ -0,0 +1,14 @@
+static dlmopen_test_spec dltest[] =
+  {
+   {
+    .name = "dlmopen-unique:X:none--ns0-ns1p",
+    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into nsX",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_NEWLM,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = PROXY,
+    .preloaded = { },
+    .loaded = { [0] = DSO|NEW, [EXPECTED_NS] = PROXY|NEW },
+   },
+   END_TESTS
+  };
diff --git a/elf/tst-dlmopen-rtld-unique4.c b/elf/tst-dlmopen-rtld-unique4.c
new file mode 100644
index 0000000000..58b8e017b4
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-unique4.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 1
+#include "tst-dlmopen-rtld-unique4.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-unique4.h b/elf/tst-dlmopen-rtld-unique4.h
new file mode 100644
index 0000000000..36d5915172
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-unique4.h
@@ -0,0 +1,15 @@
+static dlmopen_test_spec dltest[] =
+  {
+   {
+    .name = "dlmopen-shared-unique:X:none--ns0-nsXp",
+    .desc = "dlmopen a DF_GNU_1_UNIQUE dso",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_NEWLM,
+    .args.flags = RTLD_SHARED,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = PROXY,
+    .preloaded = { },
+    .loaded = { [0] = DSO|NEW, [EXPECTED_NS] = PROXY|NEW },
+   },
+   END_TESTS
+  };
diff --git a/elf/tst-dlmopen-rtld-unique5.c b/elf/tst-dlmopen-rtld-unique5.c
new file mode 100644
index 0000000000..b2e8329461
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-unique5.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 1
+#include "tst-dlmopen-rtld-unique5.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-unique5.h b/elf/tst-dlmopen-rtld-unique5.h
new file mode 100644
index 0000000000..29882ea782
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-unique5.h
@@ -0,0 +1,59 @@
+static dlmopen_test_spec dltest[] =
+  {
+   {
+    .name = "dlmopen-isolate-unique:X:none--nsX",
+    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into NSX with RTLD_ISOLATE",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_NEWLM,
+    .args.flags = RTLD_ISOLATE,
+    .handle_ns = EXPECTED_NS,
+    .free_ns = EXPECTED_NS,
+    .handle_type = DSO,
+    .preloaded = { },
+    .loaded = { [EXPECTED_NS] = DSO|NEW },
+   },
+   {
+    .name = "dlmopen-unique:0:nsX--ns0-nsX",
+    .desc = "dlmopen a DF_GNU_1_UNIQUE dso already present in NS X",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_BASE,
+    .handle_ns = 0,
+    .handle_type = DSO,
+    .preloaded = { [EXPECTED_NS] = DSO },
+    .loaded = { [0] = DSO|NEW, [EXPECTED_NS] = DSO },
+   },
+   {
+    .name = "dlmopen-unique:0:ns0-nsX--ns0-nsX",
+    .desc = "dlmopen a DF_GNU_1_UNIQUE dso already in the base NS and NS X",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_BASE,
+    .handle_ns = 0,
+    .handle_type = DSO,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+   },
+   {
+    .name = "dlmopen-shared-unique:0:ns0-nsX--ns0-nsX",
+    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso already in the base NS and NS X",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_BASE,
+    .args.flags = RTLD_SHARED,
+    .handle_ns = 0,
+    .handle_type = DSO,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+   },
+   {
+    .name = "dlmopen-shared-unique:X:ns0-nsX--ns0-nsX",
+    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso already in the base NS and NS X into NS X",
+    .failure = 1,
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = EXPECTED_NS,
+    .args.flags = RTLD_SHARED,
+    .handle_ns = EXPECTED_NS,
+    .handle_type = DSO,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+   },
+   END_TESTS
+  };
diff --git a/elf/tst-dlmopen-rtld-unique6.c b/elf/tst-dlmopen-rtld-unique6.c
new file mode 100644
index 0000000000..fecaf559a3
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-unique6.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include "tst-dlmopen-main.h"
+
+#define EXPECTED_NS 1
+#include "tst-dlmopen-rtld-unique6.h"
+
+#include "tst-dlmopen-std-do-test.h"
+
+DEFINE_DLMOPEN_TEST(dltest)
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlmopen-rtld-unique6.h b/elf/tst-dlmopen-rtld-unique6.h
new file mode 100644
index 0000000000..3c25127fa1
--- /dev/null
+++ b/elf/tst-dlmopen-rtld-unique6.h
@@ -0,0 +1,52 @@
+static dlmopen_test_spec dltest[] =
+  {
+   {
+    .name = "dlmopen-isolate-unique:1:none--ns1--prep",
+    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into NS1 with RTLD_ISOLATE",
+    .is_prep_stage = 1,
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_NEWLM,
+    .args.flags = RTLD_ISOLATE,
+    .handle_ns = EXPECTED_NS,
+    .free_ns = EXPECTED_NS,
+    .handle_type = DSO,
+    .preloaded = { },
+    .loaded = { [EXPECTED_NS] = DSO|NEW },
+   },
+   {
+    .name = "dlmopen-unique:1:nsX--nsX--FAIL",
+    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into NSX when already there",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = EXPECTED_NS,
+    .failure = 1,
+    .preloaded = { [EXPECTED_NS] = DSO },
+   },
+   {
+    .name = "dlmopen-shared-unique:X:nsX--nsX--FAIL",
+    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso into NSX when already there",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = EXPECTED_NS,
+    .args.flags = RTLD_SHARED,
+    .failure = 1,
+    .preloaded = { [EXPECTED_NS] = DSO },
+   },
+   {
+    .name = "dlmopen-shared-unique:0:nsX--ns0-nsX",
+    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso already present in NS X",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = LM_ID_BASE,
+    .handle_ns = 0,
+    .handle_type = DSO,
+    .preloaded = { [EXPECTED_NS] = DSO },
+    .loaded = { [0] = DSO|NEW, [EXPECTED_NS] = DSO },
+   },
+   {
+    .name = "dlmopen-shared-unique:X:ns0-nsX--ns0-nsX--FAIL",
+    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso already in the base NS and NS 1",
+    .args.dso_path = DSO_UNIQUE,
+    .args.ns = EXPECTED_NS,
+    .failure = 1,
+    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
+   },
+   END_TESTS
+  };
diff --git a/elf/tst-dlmopen-sharedmod-norm.c b/elf/tst-dlmopen-sharedmod-norm.c
new file mode 100644
index 0000000000..fd049903f4
--- /dev/null
+++ b/elf/tst-dlmopen-sharedmod-norm.c
@@ -0,0 +1,11 @@
+#include "tst-dlmopen-modules.h"
+
+dlmopen_testresult *rtld_shared_testfunc (void)
+{
+  static dlmopen_testresult result;
+
+  result.name = "norm";
+  result.free = free;
+
+  return &result;
+}
diff --git a/elf/tst-dlmopen-sharedmod-uniq.c b/elf/tst-dlmopen-sharedmod-uniq.c
new file mode 100644
index 0000000000..5c9701da41
--- /dev/null
+++ b/elf/tst-dlmopen-sharedmod-uniq.c
@@ -0,0 +1,11 @@
+#include "tst-dlmopen-modules.h"
+
+dlmopen_testresult *rtld_shared_testfunc (void)
+{
+  static dlmopen_testresult result;
+
+  result.name = "noop";
+  result.free = free;
+
+  return &result;
+}
diff --git a/elf/tst-dlmopen-std-do-test.h b/elf/tst-dlmopen-std-do-test.h
new file mode 100644
index 0000000000..595f6f764d
--- /dev/null
+++ b/elf/tst-dlmopen-std-do-test.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#define DEFINE_DLMOPEN_TEST(x) \
+  static int                          \
+  do_test (void)                      \
+  {                                   \
+    for (int i = 0; x[i].name; i++)   \
+      if (!process_test_spec (&x[i])) \
+        return 1;                     \
+    return 0;                         \
+  }
-- 
2.20.1


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

* [RFC][PATCH v8 20/20] Restore separate libc loading for the TLS/namespace storage test
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (18 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 19/20] Add dlmopen / RTLD_SHARED tests Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 17:18 ` Vivek Das Mohapatra via Libc-alpha
  2021-02-09 19:01 ` [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Joseph Myers
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-09 17:18 UTC (permalink / raw
  To: libc-alpha

tst-tls-ie-dlmopen checks to see that new namespaces consume
TLS memory as expected: This does not happen when new namespaces
share the same libc instance (since TLS is allocated only when
a new libc instance insitialises its threading infrastructure).

Adding RTLD_ISOLATE to the dlmopen flags in the test restores
the old behaviour which allows the test to check what it
actually needs to.
---
 elf/tst-tls-ie-dlmopen.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/elf/tst-tls-ie-dlmopen.c b/elf/tst-tls-ie-dlmopen.c
index a579d72d2d..e67017db2d 100644
--- a/elf/tst-tls-ie-dlmopen.c
+++ b/elf/tst-tls-ie-dlmopen.c
@@ -53,7 +53,7 @@ static void *
 load_and_access (Lmid_t lmid, const char *mod, const char *func)
 {
   /* Load module with TLS.  */
-  void *p = xdlmopen (lmid, mod, RTLD_NOW);
+  void *p = xdlmopen (lmid, mod, RTLD_NOW|RTLD_ISOLATE);
   /* Access the TLS variable to ensure it is allocated.  */
   void (*f) (void) = (void (*) (void))xdlsym (p, func);
   f ();
@@ -95,7 +95,7 @@ do_test (void)
      than 1024 bytes are available (exact number depends on TLS optimizations
      and the libc TLS use).  */
   printf ("The next dlmopen should fail...\n");
-  void *p = dlmopen (LM_ID_BASE, "tst-tls-ie-mod4.so", RTLD_NOW);
+  void *p = dlmopen (LM_ID_BASE, "tst-tls-ie-mod4.so", RTLD_NOW|RTLD_ISOLATE);
   if (p != NULL)
     FAIL_EXIT1 ("error: expected dlmopen to fail because there is "
 		"not enough surplus static TLS.\n");
-- 
2.20.1


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

* Re: [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (19 preceding siblings ...)
  2021-02-09 17:18 ` [RFC][PATCH v8 20/20] Restore separate libc loading for the TLS/namespace storage test Vivek Das Mohapatra via Libc-alpha
@ 2021-02-09 19:01 ` Joseph Myers
  2021-02-10 12:25   ` Vivek Das Mohapatra via Libc-alpha
  2021-02-12 18:52 ` Adhemerval Zanella via Libc-alpha
  2021-03-04 18:27 ` Adhemerval Zanella via Libc-alpha
  22 siblings, 1 reply; 78+ messages in thread
From: Joseph Myers @ 2021-02-09 19:01 UTC (permalink / raw
  To: Vivek Das Mohapatra; +Cc: libc-alpha

On Tue, 9 Feb 2021, Vivek Das Mohapatra via Libc-alpha wrote:

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

Please mention the bug number in the proposed commit messages so that 
commits get properly filed in Bugzilla.  Given the size of the patch 
series I wonder if it should also add a NEWS entry for the user-visible 
change (beyond the automatically-generated one for a bug fix generated if 
the bug is RESOLVED/FIXED with the correct target milestone set at the 
time the release is made).

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen
  2021-02-09 19:01 ` [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Joseph Myers
@ 2021-02-10 12:25   ` Vivek Das Mohapatra via Libc-alpha
  2021-02-10 18:32     ` Joseph Myers
  0 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-10 12:25 UTC (permalink / raw
  To: Joseph Myers; +Cc: libc-alpha

> Please mention the bug number in the proposed commit messages so that
> commits get properly filed in Bugzilla.  Given the size of the patch

Any particular format? And do you want the bug # in every commit message?


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

* Re: [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen
  2021-02-10 12:25   ` Vivek Das Mohapatra via Libc-alpha
@ 2021-02-10 18:32     ` Joseph Myers
  0 siblings, 0 replies; 78+ messages in thread
From: Joseph Myers @ 2021-02-10 18:32 UTC (permalink / raw
  To: Vivek Das Mohapatra; +Cc: libc-alpha

On Wed, 10 Feb 2021, Vivek Das Mohapatra via Libc-alpha wrote:

> > Please mention the bug number in the proposed commit messages so that
> > commits get properly filed in Bugzilla.  Given the size of the patch
> 
> Any particular format? And do you want the bug # in every commit message?

There are various forms such as "bug 12345" or "BZ #12345" that are 
accepted by the commit processing.

Any commit that can be considered to be the one fixing the bug should 
definitely mention the number and be explicit that it is fixing that bug.  
Any commit mentioning the number without fixing the bug should be clear 
that it is relevant to the bug, but not by itself fixing the bug.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (20 preceding siblings ...)
  2021-02-09 19:01 ` [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Joseph Myers
@ 2021-02-12 18:52 ` Adhemerval Zanella via Libc-alpha
  2021-02-12 18:56   ` Florian Weimer via Libc-alpha
  2021-02-18 14:41   ` Vivek Das Mohapatra via Libc-alpha
  2021-03-04 18:27 ` Adhemerval Zanella via Libc-alpha
  22 siblings, 2 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-12 18:52 UTC (permalink / raw
  To: Vivek Das Mohapatra, libc-alpha, Carlos O'Donell,
	Florian Weimer



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> This is a revision of a previous patchset that I posted here
> regarding https://sourceware.org/bugzilla/show_bug.cgi?id=22745 
> 
> Introduction:
> 
> =======================================================================
>   As discussed in the URL above dlmopen requires a mechanism for
>   [optionally] sharing some objects between more than one namespace.
> 
>   The following patchset provides 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 implements the following:
> 
>  - dlmopen will implicitly apply RTLD_SHARED to the libc/libpthread group
>    (requires a patched binutils/ld so that the libc family DSOs can
>    be flagged as requiring this behaviour)
> 
>    - binutils patchset accepted upstream;
>    - https://sourceware.org/git/?p=binutils-gdb.git
>    - commit 8a87b2791181eb7fc1533ffaeb95df8d87d41493
> 
>  - LD_AUDIT paths will NOT apply this implict sharing rule:
>    audit libraries will continue to be completely isolated.
> 
>  - The mechanism for tagging DSOs as implicitly shared has been changed
>    from a DT_FLAGS_1 flag to a DT_VALRNGHI/LO range dynamic section tag.
>    (Based on feedback on the binutils side of this patch series).
> 
>   - DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE
> 
>  - A flag RTLD_ISOLATE which is used inernally to suppress RTLD_SHARED
>    behaviour when audit libraries are being loaded, and is also made available
>    to users who really want a completely separate copy of glibc in their new
>    namespace.
> 
>  - Tests for the new dlmopen behaviour
> 
>  - Adds the unique dso flag to htl/libpthread.so as well as nptl

I will try to start the review of this patchset next week, I still reading
all the history and provided links but the idea is sound. And my sniff
tests did triggered any warnings.

Carlos started to review it on previous iterations, so I take he agrees
this should a good addition as well.

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

Could you extend what semantic and useful would to add such extension?

> 
>  - dl_iterate_ns_phdr (cf dl_iterate_phdr but taking a namespace argument)

I think if we agree to add this extension we might also work around the
current issues of dl_iterate_phdr.  If I recall correctly, Florian has
raised the current scalability issues and proposed a better replacement
in a previous Cauldron.

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

* Re: [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen
  2021-02-12 18:52 ` Adhemerval Zanella via Libc-alpha
@ 2021-02-12 18:56   ` Florian Weimer via Libc-alpha
  2021-02-12 19:01     ` Adhemerval Zanella via Libc-alpha
  2021-02-18 14:41   ` Vivek Das Mohapatra via Libc-alpha
  1 sibling, 1 reply; 78+ messages in thread
From: Florian Weimer via Libc-alpha @ 2021-02-12 18:56 UTC (permalink / raw
  To: Adhemerval Zanella; +Cc: libc-alpha

* Adhemerval Zanella:

>>  - dl_iterate_ns_phdr (cf dl_iterate_phdr but taking a namespace argument)
>
> I think if we agree to add this extension we might also work around the
> current issues of dl_iterate_phdr.  If I recall correctly, Florian has
> raised the current scalability issues and proposed a better replacement
> in a previous Cauldron.

Iterating over link maps in a namespace is still indepedently useful.
I just don't think it's the right interface for locating exception
unwinding information based on a code address.

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


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

* Re: [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen
  2021-02-12 18:56   ` Florian Weimer via Libc-alpha
@ 2021-02-12 19:01     ` Adhemerval Zanella via Libc-alpha
  2021-02-12 19:29       ` Florian Weimer via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-12 19:01 UTC (permalink / raw
  To: Florian Weimer; +Cc: libc-alpha



On 12/02/2021 15:56, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>>>  - dl_iterate_ns_phdr (cf dl_iterate_phdr but taking a namespace argument)
>>
>> I think if we agree to add this extension we might also work around the
>> current issues of dl_iterate_phdr.  If I recall correctly, Florian has
>> raised the current scalability issues and proposed a better replacement
>> in a previous Cauldron.
> 
> Iterating over link maps in a namespace is still indepedently useful.
> I just don't think it's the right interface for locating exception
> unwinding information based on a code address.

If I recall correctly you also brought some scalability issue due the
internal locking, or am I missing something?

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

* Re: [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen
  2021-02-12 19:01     ` Adhemerval Zanella via Libc-alpha
@ 2021-02-12 19:29       ` Florian Weimer via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Florian Weimer via Libc-alpha @ 2021-02-12 19:29 UTC (permalink / raw
  To: Adhemerval Zanella; +Cc: libc-alpha

* Adhemerval Zanella:

> On 12/02/2021 15:56, Florian Weimer wrote:
>> * Adhemerval Zanella:
>> 
>>>>  - dl_iterate_ns_phdr (cf dl_iterate_phdr but taking a namespace argument)
>>>
>>> I think if we agree to add this extension we might also work around the
>>> current issues of dl_iterate_phdr.  If I recall correctly, Florian has
>>> raised the current scalability issues and proposed a better replacement
>>> in a previous Cauldron.
>> 
>> Iterating over link maps in a namespace is still indepedently useful.
>> I just don't think it's the right interface for locating exception
>> unwinding information based on a code address.
>
> If I recall correctly you also brought some scalability issue due the
> internal locking, or am I missing something?

Yes, but it's hard to tell if it matters to other use cases for
iteration without looking at them individually.

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


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

* Re: [RFC][PATCH v8 01/20] Declare and describe the dlmopen RTLD_SHARED flag
  2021-02-09 17:18 ` [RFC][PATCH v8 01/20] Declare and describe the dlmopen RTLD_SHARED flag Vivek Das Mohapatra via Libc-alpha
@ 2021-02-15 13:08   ` Adhemerval Zanella via Libc-alpha
  2021-02-15 13:29     ` Andreas Schwab
  0 siblings, 1 reply; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-15 13:08 UTC (permalink / raw
  To: Vivek Das Mohapatra, libc-alpha



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> 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.

This patch should combined with the 4th of the set (elf/dl-load.c, 
elf-dl-open.c: Implement RTLD_SHARED dlmopen proxying) which is the 
first one that actually uses the RTLD_SHARED flag.

> ---
>  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 f3bc63e958..0daa789693 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.  */

I think this should be add as GNU extension for now, which mean within
the __USE_GNU ifdef (even though RTLD_NODELETE, RTLD_NOLOAD, and
RTLD_DEEPBIND now currently exported as GNU extension).

> diff --git a/sysdeps/mips/bits/dlfcn.h b/sysdeps/mips/bits/dlfcn.h
> index 5cec898de3..1331771a17 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.  */
> 

Same as before.

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

* Re: [RFC][PATCH v8 02/20] include/link.h: Update the link_map struct to allow proxies
  2021-02-09 17:18 ` [RFC][PATCH v8 02/20] include/link.h: Update the link_map struct to allow proxies Vivek Das Mohapatra via Libc-alpha
@ 2021-02-15 13:11   ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-15 13:11 UTC (permalink / raw
  To: libc-alpha



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> 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.

As for the first patch, this one should also be combined with the 4th 
of the set.

> ---
>  include/link.h | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/include/link.h b/include/link.h
> index 4af16cb596..b51fa0cbdf 100644
> --- a/include/link.h
> +++ b/include/link.h
> @@ -107,8 +107,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.  */
> @@ -180,6 +181,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.  */
> 

Ok.

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

* Re: [RFC][PATCH v8 01/20] Declare and describe the dlmopen RTLD_SHARED flag
  2021-02-15 13:08   ` Adhemerval Zanella via Libc-alpha
@ 2021-02-15 13:29     ` Andreas Schwab
  2021-02-15 13:31       ` Adhemerval Zanella via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Andreas Schwab @ 2021-02-15 13:29 UTC (permalink / raw
  To: Adhemerval Zanella via Libc-alpha

On Feb 15 2021, Adhemerval Zanella via Libc-alpha wrote:

> I think this should be add as GNU extension for now, which mean within
> the __USE_GNU ifdef (even though RTLD_NODELETE, RTLD_NOLOAD, and
> RTLD_DEEPBIND now currently exported as GNU extension).

I don't think this is needed, as all RTLD_ names are reserved for
<dlfcn.h>.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."

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

* Re: [RFC][PATCH v8 03/20] elf/dl-object.c: Implement a helper function to proxy link_map entries
  2021-02-09 17:18 ` [RFC][PATCH v8 03/20] elf/dl-object.c: Implement a helper function to proxy link_map entries Vivek Das Mohapatra via Libc-alpha
@ 2021-02-15 13:30   ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-15 13:30 UTC (permalink / raw
  To: Vivek Das Mohapatra, libc-alpha



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> Provides the minimal functionality needed to take an existing
> link_map entry and create a proxy for it in the specified namespace.

This patch also should be combined with the 4th of the set, even though
it would incur a larger patch.

> ---
>  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 1875599eb2..1a9d35c96b 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;

No implicit chech (even though there are copies from older implementations):

  while (old != NULL && old->l_proxy)

I am not sure though about bit-fields checks, I think implicit check as
booleans should be fine.

> +
> +  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

Double space after period.

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

Not sure if this check make sense, from the 'while' above 'old' will be
either null (which will be bail out with the _dl_signal_error above)
or old->l_proxy would not be true.

> +
> +      _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"));

Indentation seems of here.

> +
> +  /* 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

Double space after period.

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

Indentation seems of here.

> +
> +  /* 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 9720a4e446..f58b4ac49f 100644
> --- a/sysdeps/generic/ldsodefs.h
> +++ b/sysdeps/generic/ldsodefs.h
> @@ -974,6 +974,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;
>  
>  /* Restricted version of _dl_lookup_symbol_x.  Searches MAP (and only
>     MAP) for the symbol UNDEF_NAME, with GNU hash NEW_HASH (computed
> 

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

* Re: [RFC][PATCH v8 01/20] Declare and describe the dlmopen RTLD_SHARED flag
  2021-02-15 13:29     ` Andreas Schwab
@ 2021-02-15 13:31       ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-15 13:31 UTC (permalink / raw
  To: Andreas Schwab, Adhemerval Zanella via Libc-alpha



On 15/02/2021 10:29, Andreas Schwab wrote:
> On Feb 15 2021, Adhemerval Zanella via Libc-alpha wrote:
> 
>> I think this should be add as GNU extension for now, which mean within
>> the __USE_GNU ifdef (even though RTLD_NODELETE, RTLD_NOLOAD, and
>> RTLD_DEEPBIND now currently exported as GNU extension).
> 
> I don't think this is needed, as all RTLD_ names are reserved for
> <dlfcn.h>.

Fair enough.

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

* Re: [RFC][PATCH v8 04/20] elf/dl-load.c, elf-dl-open.c: Implement RTLD_SHARED dlmopen proxying
  2021-02-09 17:18 ` [RFC][PATCH v8 04/20] elf/dl-load.c, elf-dl-open.c: Implement RTLD_SHARED dlmopen proxying Vivek Das Mohapatra via Libc-alpha
@ 2021-02-15 14:53   ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-15 14:53 UTC (permalink / raw
  To: libc-alpha, Vivek Das Mohapatra



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> 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 | 60 +++++++++++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 104 insertions(+), 2 deletions(-)
> 
> diff --git a/elf/dl-load.c b/elf/dl-load.c
> index 9e2089cfaa..3c5f667717 100644
> --- a/elf/dl-load.c
> +++ b/elf/dl-load.c
> @@ -2006,6 +2006,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)

No implicit checks (even though this originated from ancient code).

  for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)

> +    {
> +      if (__glibc_unlikely ((l->l_faked | l->l_removed) != 0))
> +        continue;
> +
> +      if (!_dl_name_match_p (name, l))
> +        continue;

Ok (although it would make sense to change _dl_name_match_p to
return a bool).

> +
> +      /* We have a match - stop searching.  */
> +      break;
> +    }
> +
> +  if (l)

No implicit checks.

> +    {
> +      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.  */
>  

Ok.

>  struct link_map *
> @@ -2022,6 +2054,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.  */

I am not sure if grave accent should be used on newer code (afaik our
git commit hooks refuses it on commit messages).

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

Space after 'if'.  Also I think it usual to not put attribution inside an
if:
  
  l = _dl_find_proxy (nsid, name);
  if (l != NULL)
    return l;

> +        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 ab7aaa345e..4cb90bfe19 100644
> --- a/elf/dl-open.c
> +++ b/elf/dl-open.c
> @@ -484,6 +484,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;

Use 'bool' here.

> +  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
> @@ -508,6 +510,15 @@ dl_open_worker (void *a)
>  	args->nsid = call_map->l_ns;
>      }
>  
> +  /* Now that we know the NS for sure, sanity check the mode.  */
> +  if (__glibc_likely(args->nsid == LM_ID_BASE) &&

Space '__glibc_likely' and '__glibc_unlikely'.

> +      __glibc_unlikely(mode & RTLD_SHARED))
> +    {
> +      args->mode &= ~RTLD_SHARED;
> +      mode &= ~RTLD_SHARED;
> +      want_proxy = 0;
> +    }
> +
>    /* The namespace ID is now known.  Keep track of whether libc.so was
>       already loaded, to determine whether it is necessary to call the
>       early initialization routine (or clear libc_map on error).  */
> @@ -541,6 +552,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

As before I think it should use apostrophe instead of grave accent.

> +     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))
>      {

Ok.

> @@ -572,6 +601,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;
>      }
>  

OK.

> @@ -787,10 +826,27 @@ 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;
> +    }
> +
>    /* 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 *
> 

Ok.

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

* Re: [RFC][PATCH v8 05/20] elf/dl-fini.c: Handle proxy link_map entries in the shutdown path
  2021-02-09 17:18 ` [RFC][PATCH v8 05/20] elf/dl-fini.c: Handle proxy link_map entries in the shutdown path Vivek Das Mohapatra via Libc-alpha
@ 2021-02-15 17:08   ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-15 17:08 UTC (permalink / raw
  To: libc-alpha, Vivek Das Mohapatra



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> 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 c51becd06b..a0432b884d 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,

Ok.

> @@ -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.  */

Ok.

> @@ -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.  */

Ok.

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

Ok.

> diff --git a/elf/dl-fini.c b/elf/dl-fini.c
> index 6dbdfe4b3e..10194488bb 100644
> --- a/elf/dl-fini.c
> +++ b/elf/dl-fini.c
> @@ -73,7 +73,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);
>  
> @@ -111,7 +111,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;
> 

Ok.

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

* Re: [RFC][PATCH v8 06/20] elf/dl-init.c: Skip proxied link map entries in the dl init path
  2021-02-09 17:18 ` [RFC][PATCH v8 06/20] elf/dl-init.c: Skip proxied link map entries in the dl init path Vivek Das Mohapatra via Libc-alpha
@ 2021-02-15 17:52   ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-15 17:52 UTC (permalink / raw
  To: Vivek Das Mohapatra, libc-alpha



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> 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 b7e4b8a3af..a0183aa315 100644
> --- a/elf/dl-init.c
> +++ b/elf/dl-init.c
> @@ -34,8 +34,8 @@ call_init (struct link_map *l, int argc, char **argv, char **env)
>       need relocation, and neither do proxy objects.)  */
>    assert (l->l_real->l_relocated || l->l_real->l_type == lt_executable);
>  
> -  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
> 

Ok.

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

* Re: [RFC][PATCH v8 07/20] elf/dl-open.c: Don't try libc linit in namespaces with no libc mapping
  2021-02-09 17:18 ` [RFC][PATCH v8 07/20] elf/dl-open.c: Don't try libc linit in namespaces with no libc mapping Vivek Das Mohapatra via Libc-alpha
@ 2021-02-15 17:54   ` Adhemerval Zanella via Libc-alpha
  2021-02-17 15:39     ` Vivek Das Mohapatra via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-15 17:54 UTC (permalink / raw
  To: libc-alpha



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> Secondary namespaces which share their libc mapping with the main
> namespace cannot (and should not) have _dl_call_libc_early_init
> called for them by dl_open_worker.
> ---
>  elf/dl-open.c | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)
> 
> diff --git a/elf/dl-open.c b/elf/dl-open.c
> index 4cb90bfe19..dc4b386559 100644
> --- a/elf/dl-open.c
> +++ b/elf/dl-open.c
> @@ -792,16 +792,21 @@ dl_open_worker (void *a)
>       namespace.  */
>    if (!args->libc_already_loaded)
>      {
> +      /* If this is a secondary (nsid != LM_ID_BASE) namespace then
> +         it is POSSIBLE there's no libc_map at all - We use the one
> +         shared with LM_ID_BASE instead (which MUST already be
> +         initialised for us to even reach here).  */
>        struct link_map *libc_map = GL(dl_ns)[args->nsid].libc_map;
>  #ifdef SHARED
> -      bool initial = libc_map->l_ns == LM_ID_BASE;
> +      bool initial = libc_map && (libc_map->l_real->l_ns == LM_ID_BASE);

No implicit checks.

>  #else
>        /* In the static case, there is only one namespace, but it
>  	 contains a secondary libc (the primary libc is statically
>  	 linked).  */
>        bool initial = false;
>  #endif
> -      _dl_call_libc_early_init (libc_map, initial);
> +      if (libc_map != NULL)
> +        _dl_call_libc_early_init (libc_map, initial);
>      }
>  
>  #ifndef SHARED
> 

Ok.

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

* Re: [RFC][PATCH v8 08/20] elf/dl-open.c: when creating a proxy check the libc_map in NS 0
  2021-02-09 17:18 ` [RFC][PATCH v8 08/20] elf/dl-open.c: when creating a proxy check the libc_map in NS 0 Vivek Das Mohapatra via Libc-alpha
@ 2021-02-15 17:55   ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-15 17:55 UTC (permalink / raw
  To: libc-alpha



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> The libc_already_loaded check normally considers the libc_map entry
> in GL(dl_ns)[args->nsid].libc_map.
> 
> This is not correct for proxies, which use the libc_map from
> the default namespace (as proxies are dummy entries that point
> to the base namespace via their l_real members).
> ---
>  elf/dl-open.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/elf/dl-open.c b/elf/dl-open.c
> index dc4b386559..096aa4c680 100644
> --- a/elf/dl-open.c
> +++ b/elf/dl-open.c
> @@ -568,6 +568,7 @@ dl_open_worker (void *a)
>      {
>        proxy_ns = args->nsid;
>        args->nsid = LM_ID_BASE;
> +      args->libc_already_loaded = GL(dl_ns)[LM_ID_BASE].libc_map != NULL;
>      }
>  
>    /* It was already open.  */
> 

Ok.

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

* Re: [RFC][PATCH v8 09/20] Define a new dynamic section tag - DT_GNU_FLAGS_1
  2021-02-09 17:18 ` [RFC][PATCH v8 09/20] Define a new dynamic section tag - DT_GNU_FLAGS_1 Vivek Das Mohapatra via Libc-alpha
@ 2021-02-15 18:42   ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-15 18:42 UTC (permalink / raw
  To: libc-alpha



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> Define a new flags section DT_GNU_FLAGS_1 (no more bits are available
> in DT_GNU_FLAGS).
> 
> One flag is currently defined: DF_GNU_1_UNIQUE.
> 
> libc and its companion DSOs (libpthread et al) should have this
> section and flag set.
> ---
>  elf/elf.h              |  7 ++++++-
>  elf/get-dynamic-info.h | 12 ++++++++++++
>  include/elf.h          |  2 ++
>  include/link.h         |  1 +
>  4 files changed, 21 insertions(+), 1 deletion(-)
> 
> diff --git a/elf/elf.h b/elf/elf.h
> index 4f838d4af2..9f9b8e4291 100644
> --- a/elf/elf.h
> +++ b/elf/elf.h
> @@ -895,6 +895,7 @@ typedef struct
>     Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
>     approach.  */
>  #define DT_VALRNGLO	0x6ffffd00
> +#define DT_GNU_FLAGS_1   0x6ffffdf4    /* Open DSO once across all namespaces */
>  #define DT_GNU_PRELINKED 0x6ffffdf5	/* Prelinking timestamp */
>  #define DT_GNU_CONFLICTSZ 0x6ffffdf6	/* Size of conflict section */
>  #define DT_GNU_LIBLISTSZ 0x6ffffdf7	/* Size of library list */

Ok, it matches binutils definition.

> @@ -909,7 +910,7 @@ typedef struct
>  #define DT_SYMINENT	0x6ffffdff	/* Entry size of syminfo */
>  #define DT_VALRNGHI	0x6ffffdff
>  #define DT_VALTAGIDX(tag)	(DT_VALRNGHI - (tag))	/* Reverse order! */
> -#define DT_VALNUM 12
> +#define DT_VALNUM 13
>  
Ok.

>  /* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
>     Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
> @@ -998,6 +999,10 @@ typedef struct
>  #define	DF_1_WEAKFILTER 0x20000000
>  #define	DF_1_NOCOMMON   0x40000000
>  
> +/* State flags selectable in the `d_un.d_val' element of the DT_GNU_FLAGS_1
> +   entry in the dynamic section.  */
> +#define DF_GNU_1_UNIQUE 0x00000001
> +
>  /* Flags for the feature selection in DT_FEATURE_1.  */
>  #define DTF_1_PARINIT	0x00000001
>  #define DTF_1_CONFEXP	0x00000002

Ok, it matches binutils definition.

> diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
> index d8ec32377d..d441b39576 100644
> --- a/elf/get-dynamic-info.h
> +++ b/elf/get-dynamic-info.h
> @@ -175,6 +175,18 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
>        if (l->l_flags_1 & DF_1_NOW)
>  	info[DT_BIND_NOW] = info[VERSYMIDX (DT_FLAGS_1)];
>      }
> +  if (info[DT_VALTAGIDX (DT_GNU_FLAGS_1)
> +           + DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM] != NULL)
> +    {
> +      l->l_gnu_flags_1 = info[DT_VALTAGIDX (DT_GNU_FLAGS_1)
> +                              + DT_NUM + DT_THISPROCNUM
> +                              + DT_VERSIONTAGNUM + DT_EXTRANUM]->d_un.d_val;
> +
> +      if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)
> +	  && l->l_gnu_flags_1 & ~DT_GNU_1_SUPPORTED_MASK)

Use __glibc_likely.

> +	_dl_debug_printf ("\nWARNING: Unsupported flag value(s) of 0x%x in DT_GNU_FLAGS_1.\n",
> +			  l->l_gnu_flags_1 & ~DT_GNU_1_SUPPORTED_MASK);
> +    }
>    if (info[DT_RUNPATH] != NULL)
>      /* If both RUNPATH and RPATH are given, the latter is ignored.  */
>      info[DT_RPATH] = NULL;

Ok.

> diff --git a/include/elf.h b/include/elf.h
> index 14ed67ff67..5eee37c294 100644
> --- a/include/elf.h
> +++ b/include/elf.h
> @@ -25,5 +25,7 @@
>     (DF_1_NOW | DF_1_NODELETE | DF_1_INITFIRST | DF_1_NOOPEN \
>      | DF_1_ORIGIN | DF_1_NODEFLIB | DF_1_PIE)
>  
> +#define DT_GNU_1_SUPPORTED_MASK DF_GNU_1_UNIQUE
> +
>  #endif /* !_ISOMAC */
>  #endif /* elf.h */

Ok.

> diff --git a/include/link.h b/include/link.h
> index b51fa0cbdf..55e0cad71d 100644
> --- a/include/link.h
> +++ b/include/link.h
> @@ -285,6 +285,7 @@ struct link_map
>      unsigned int l_used;
>  
>      /* Various flag words.  */
> +    ElfW(Word) l_gnu_flags_1;
>      ElfW(Word) l_feature_1;
>      ElfW(Word) l_flags_1;
>      ElfW(Word) l_flags;
> 

Ok.

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

* Re: [RFC][PATCH v8 10/20] Abstract the loaded-DSO search code into a private helper function
  2021-02-09 17:18 ` [RFC][PATCH v8 10/20] Abstract the loaded-DSO search code into a private helper function Vivek Das Mohapatra via Libc-alpha
@ 2021-02-15 19:25   ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-15 19:25 UTC (permalink / raw
  To: libc-alpha, Vivek Das Mohapatra



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> ---
>  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 3c5f667717..2a01ab7ad2 100644
> --- a/elf/dl-load.c
> +++ b/elf/dl-load.c
> @@ -2038,6 +2038,44 @@ _dl_find_proxy (Lmid_t nsid, const char *name)
>    return NULL;
>  }
>  
> +/* search for a shared object in a given namespace.  */

Maybe capitalize the 'search'?  

> +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 *

Ok,

> diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
> index f58b4ac49f..d0b9a22779 100644
> --- a/sysdeps/generic/ldsodefs.h
> +++ b/sysdeps/generic/ldsodefs.h
> @@ -1242,6 +1242,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;
> 

Ok.

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

* Re: [RFC][PATCH v8 07/20] elf/dl-open.c: Don't try libc linit in namespaces with no libc mapping
  2021-02-15 17:54   ` Adhemerval Zanella via Libc-alpha
@ 2021-02-17 15:39     ` Vivek Das Mohapatra via Libc-alpha
  2021-02-17 16:17       ` Adhemerval Zanella via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-17 15:39 UTC (permalink / raw
  To: Adhemerval Zanella; +Cc: libc-alpha

>>  #ifdef SHARED
>> -      bool initial = libc_map->l_ns == LM_ID_BASE;
>> +      bool initial = libc_map && (libc_map->l_real->l_ns == LM_ID_BASE);
>
> No implicit checks.

Sorry - It's not clear to me what change you want here.

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

* Re: [RFC][PATCH v8 07/20] elf/dl-open.c: Don't try libc linit in namespaces with no libc mapping
  2021-02-17 15:39     ` Vivek Das Mohapatra via Libc-alpha
@ 2021-02-17 16:17       ` Adhemerval Zanella via Libc-alpha
  2021-02-17 18:32         ` Vivek Das Mohapatra via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-17 16:17 UTC (permalink / raw
  To: Vivek Das Mohapatra; +Cc: libc-alpha



On 17/02/2021 12:39, Vivek Das Mohapatra wrote:
>>>  #ifdef SHARED
>>> -      bool initial = libc_map->l_ns == LM_ID_BASE;
>>> +      bool initial = libc_map && (libc_map->l_real->l_ns == LM_ID_BASE);
>>
>> No implicit checks.
> 
> Sorry - It's not clear to me what change you want here.

The libc_map is a pointer here, so:

 bool initial = libc_map != NULL && libc_map->l_real->l_ns == LM_ID_BASE;

(is libc_map->l_real always valid here btw?)

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

* Re: [RFC][PATCH v8 07/20] elf/dl-open.c: Don't try libc linit in namespaces with no libc mapping
  2021-02-17 16:17       ` Adhemerval Zanella via Libc-alpha
@ 2021-02-17 18:32         ` Vivek Das Mohapatra via Libc-alpha
  2021-02-17 20:52           ` Adhemerval Zanella via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-17 18:32 UTC (permalink / raw
  To: Adhemerval Zanella; +Cc: libc-alpha

> The libc_map is a pointer here, so:
>
> bool initial = libc_map != NULL && libc_map->l_real->l_ns == LM_ID_BASE;

Ah, got it. Will do,

> (is libc_map->l_real always valid here btw?)

Yes: _dl_new_object assigns it immediately after calloc'ing the
link map entry struct. _dl_new_proxy does similar and the only
other case is ld.so itself which also has l_real assigned
early.

_dl_init asserts that ->l_real-><something> is non NULL too
so the assumption that l_real is dereferencable is pretty
widespread and fundamental.


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

* Re: [RFC][PATCH v8 07/20] elf/dl-open.c: Don't try libc linit in namespaces with no libc mapping
  2021-02-17 18:32         ` Vivek Das Mohapatra via Libc-alpha
@ 2021-02-17 20:52           ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-17 20:52 UTC (permalink / raw
  To: Vivek Das Mohapatra; +Cc: libc-alpha



On 17/02/2021 15:32, Vivek Das Mohapatra wrote:
>> The libc_map is a pointer here, so:
>>
>> bool initial = libc_map != NULL && libc_map->l_real->l_ns == LM_ID_BASE;
> 
> Ah, got it. Will do,

Thanks, I will try to finish the set review by the end of the week.

> 
>> (is libc_map->l_real always valid here btw?)
> 
> Yes: _dl_new_object assigns it immediately after calloc'ing the
> link map entry struct. _dl_new_proxy does similar and the only
> other case is ld.so itself which also has l_real assigned
> early.
> 
> _dl_init asserts that ->l_real-><something> is non NULL too
> so the assumption that l_real is dereferencable is pretty
> widespread and fundamental.
> 

Ack.

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

* Re: [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen
  2021-02-12 18:52 ` Adhemerval Zanella via Libc-alpha
  2021-02-12 18:56   ` Florian Weimer via Libc-alpha
@ 2021-02-18 14:41   ` Vivek Das Mohapatra via Libc-alpha
  2021-02-18 15:02     ` Florian Weimer via Libc-alpha
  1 sibling, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-18 14:41 UTC (permalink / raw
  To: Adhemerval Zanella; +Cc: Florian Weimer, libc-alpha

>> 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
>
> Could you extend what semantic and useful would to add such extension?

Right now RTLD_GLOBAL is well defined for the main namespace.

It isn't defined at all for secondary namespaces (and tends to
result in a segfault when passed to dlmopen).

I would propose something like this:

Main namespace RTLD_GLOBAL - works as at present. The new
(or newly promoted) DSO is implicitly available for symbol
resolution from/by all main namespace DSOs.

Secondary namespace RTLD_GLOBAL - the new or newly promoted
DSO is implicitly available for symbol resolution from/by
all DSOs _in that namespace_.


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

* Re: [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen
  2021-02-18 14:41   ` Vivek Das Mohapatra via Libc-alpha
@ 2021-02-18 15:02     ` Florian Weimer via Libc-alpha
  2021-02-18 15:05       ` Vivek Das Mohapatra via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Florian Weimer via Libc-alpha @ 2021-02-18 15:02 UTC (permalink / raw
  To: Vivek Das Mohapatra via Libc-alpha

* Vivek Das Mohapatra via Libc-alpha:

> I would propose something like this:
>
> Main namespace RTLD_GLOBAL - works as at present. The new
> (or newly promoted) DSO is implicitly available for symbol
> resolution from/by all main namespace DSOs.
>
> Secondary namespace RTLD_GLOBAL - the new or newly promoted
> DSO is implicitly available for symbol resolution from/by
> all DSOs _in that namespace_.

That makes sense to me.

We currently delay the update of the global scope after ELF constructors
of new objects are invoked.  Is this something we should keep (in both
cases)?

Thanks,
Florian


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

* Re: [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen
  2021-02-18 15:02     ` Florian Weimer via Libc-alpha
@ 2021-02-18 15:05       ` Vivek Das Mohapatra via Libc-alpha
  2021-02-19  8:57         ` Florian Weimer via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-18 15:05 UTC (permalink / raw
  To: Florian Weimer; +Cc: Vivek Das Mohapatra via Libc-alpha

> We currently delay the update of the global scope after ELF constructors
> of new objects are invoked.  Is this something we should keep (in both
> cases)?

I think so - make sure everything is consistent and settled before exposing
it to the rest of the world.


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

* Re: [RFC][PATCH v8 11/20] Compare loaded DSOs by file ID and check for DF_GNU_1_UNIQUE
  2021-02-09 17:18 ` [RFC][PATCH v8 11/20] Compare loaded DSOs by file ID and check for DF_GNU_1_UNIQUE Vivek Das Mohapatra via Libc-alpha
@ 2021-02-18 20:45   ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-18 20:45 UTC (permalink / raw
  To: libc-alpha, Vivek Das Mohapatra



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> 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_GNU_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

s/dontinue/continue.

> 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 2a01ab7ad2..780bca99e8 100644
> --- a/elf/dl-load.c
> +++ b/elf/dl-load.c
> @@ -1020,6 +1020,32 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
>      }
>  #endif
>  
> +  /* DSOs in the main namespace which are flagged DF_GNU_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_gnu_flags_1 & DF_GNU_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 */

Missing period and double space before comment end.

> +            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 096aa4c680..441b8b1330 100644
> --- a/elf/dl-open.c
> +++ b/elf/dl-open.c
> @@ -561,6 +561,16 @@ dl_open_worker (void *a)
>        return;
>      }
>  
> +  /* If we are trying to load a DF_GNU_1_UNIQUE flagged DSO which was
> +     NOT ALREADY LOADED (or not loaded with the name we are using) then
> +     _dl_map_object will have returned 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))

Space before '(' 

> +    {
> +      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.  */
> 

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

* Re: [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen
  2021-02-18 15:05       ` Vivek Das Mohapatra via Libc-alpha
@ 2021-02-19  8:57         ` Florian Weimer via Libc-alpha
  2021-02-19 15:08           ` Vivek Das Mohapatra via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Florian Weimer via Libc-alpha @ 2021-02-19  8:57 UTC (permalink / raw
  To: Vivek Das Mohapatra; +Cc: Vivek Das Mohapatra via Libc-alpha

* Vivek Das Mohapatra:

>> We currently delay the update of the global scope after ELF constructors
>> of new objects are invoked.  Is this something we should keep (in both
>> cases)?
>
> I think so - make sure everything is consistent and settled before exposing
> it to the rest of the world.

But the shared objects are available on the local scope before
initialization (and it has to be this way).  So there's still an
inconsistency.

The technical problem here is that adding things to the global scope may
require memory allocation, and that can fail.  But after we have called
any ELF constructors, dlopen must not fail.  So we have to pre-allocate
any changes, and that code is a bit weird, particularly due to recursive
dlopen.

Thanks,
Florian


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

* Re: [RFC][PATCH v8 12/20] Use the new DSO finder helper function since we have it
  2021-02-09 17:18 ` [RFC][PATCH v8 12/20] Use the new DSO finder helper function since we have it Vivek Das Mohapatra via Libc-alpha
@ 2021-02-19 14:39   ` Adhemerval Zanella via Libc-alpha
  2021-02-19 19:50     ` Adhemerval Zanella via Libc-alpha
  2021-02-22 18:44     ` Vivek Das Mohapatra via Libc-alpha
  0 siblings, 2 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-19 14:39 UTC (permalink / raw
  To: libc-alpha, Vivek Das Mohapatra



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> ---
>  elf/dl-load.c | 43 +++++++++++++++++--------------------------
>  1 file changed, 17 insertions(+), 26 deletions(-)
> 
> diff --git a/elf/dl-load.c b/elf/dl-load.c
> index 780bca99e8..13ac2053b8 100644
> --- a/elf/dl-load.c
> +++ b/elf/dl-load.c
> @@ -2133,35 +2133,26 @@ _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)
> +  l = _dl_find_dso (name, nsid);
> +
> +  if (l != NULL)
>      {
> -      /* 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.  */
> +#ifdef SHARED
> +      /* If we are trying to load a DF_GNU_1_UNIQUE flagged DSO which WAS
> +         already opened in the target NS but with RTLD_ISOLATE so it WAS NOT
> +         created as a proxy we need to error out since we cannot satisfy the
> +         DF_GNU_1_UNIQUE is-equivalent-to RTLD_SHARED semantics.  */
> +      if (!(mode & RTLD_ISOLATE) &&
> +          (l->l_ns != LM_ID_BASE) &&
> +          (l->l_gnu_flags_1 & DF_GNU_1_UNIQUE) &&
> +          !l->l_proxy)
> +      {
> +        _dl_signal_error (EEXIST, name, NULL,
> +                          N_("object cannot be demoted to a proxy"));
> +      }
> +#endif
>        return l;

I think this patch should reorganized along with the previous, where
first you refactor the code to use find_dso and *then* add the
required l_proxy change in a subsequent patch.

(There are other patch organization that I think should be changed,
I will get back to them once I finish reviewing the set)

>      }
> -

I usually avoid such spurious change.

>    /* Display information if we are debugging.  */
>    if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)
>        && loader != NULL)
> 

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

* Re: [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen
  2021-02-19  8:57         ` Florian Weimer via Libc-alpha
@ 2021-02-19 15:08           ` Vivek Das Mohapatra via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-19 15:08 UTC (permalink / raw
  To: Florian Weimer; +Cc: Vivek Das Mohapatra via Libc-alpha

> But the shared objects are available on the local scope before
> initialization (and it has to be this way).  So there's still an
> inconsistency.
>
> The technical problem here is that adding things to the global scope may
> require memory allocation, and that can fail.  But after we have called
> any ELF constructors, dlopen must not fail.  So we have to pre-allocate
> any changes, and that code is a bit weird, particularly due to recursive
> dlopen.

Hm. Well, I guess my answer would be that it should work the same way
for both cases: Otherwise we're introducing a weird (as well as obscure
and surprising) inconsistency between primary and secondary namespaces.





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

* Re: [RFC][PATCH v8 13/20] Use the DSO search helper to check for preloaded DT_GNU_UNIQUE DSOs
  2021-02-09 17:18 ` [RFC][PATCH v8 13/20] Use the DSO search helper to check for preloaded DT_GNU_UNIQUE DSOs Vivek Das Mohapatra via Libc-alpha
@ 2021-02-19 17:26   ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-19 17:26 UTC (permalink / raw
  To: libc-alpha



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> 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-open.c | 18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
> 
> diff --git a/elf/dl-open.c b/elf/dl-open.c
> index 441b8b1330..38b3587d4a 100644
> --- a/elf/dl-open.c
> +++ b/elf/dl-open.c
> @@ -484,6 +484,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;
>  
> @@ -532,6 +533,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_FLAGS_1/DF_GNU_1_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))

'want_proxy' is an int, check against '0'.

> +    {
> +      preloaded = _dl_find_dso (file, LM_ID_BASE);
> +
> +      if (preloaded && (preloaded->l_gnu_flags_1 & DF_GNU_1_UNIQUE))

No implicit checks.

> +        {
> +          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,
> 

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

* Re: [RFC][PATCH v8 14/20] When loading DSOs into alternate namespaces check for DT_GNU_UNIQUE
  2021-02-09 17:18 ` [RFC][PATCH v8 14/20] When loading DSOs into alternate namespaces check for DT_GNU_UNIQUE Vivek Das Mohapatra via Libc-alpha
@ 2021-02-19 18:11   ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-19 18:11 UTC (permalink / raw
  To: Vivek Das Mohapatra, libc-alpha



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> 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 DT_GNU_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 | 96 +++++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 82 insertions(+), 14 deletions(-)
> 
> diff --git a/elf/dl-load.c b/elf/dl-load.c
> index 13ac2053b8..13879af82c 100644
> --- a/elf/dl-load.c
> +++ b/elf/dl-load.c
> @@ -837,6 +837,62 @@ _dl_init_paths (const char *llp, const char *source,
>      __rtld_env_path_list.dirs = (void *) -1;
>  }
>  
> +static ElfW(Word)
> +_has_gnu_unique (int fd, const ElfW(Ehdr) *header, const ElfW(Phdr) *phdr)

I think it make sense to make it return a 'bool' and there is no need to
prepend the function name '_' since it is static.

> +{
> +  int unique = 0;
> +  const ElfW(Phdr) *ph;
> +  ElfW(Dyn) entry = {};

It seems the only field really required to be initialized is d_tag.

> +  off_t reset;
> +  off_t pos;
> +  off_t end;
> +
> +  reset = __lseek (fd, 0, SEEK_CUR);

I think newer code should not use non-LFS interfaces, it means replace
off_t with off64_t and __lseek with __lseek64.

> +
> +  for (ph = phdr; ph < &phdr[header->e_phnum]; ++ph)
> +    {
> +      switch (ph->p_type)
> +	{
> +        case PT_DYNAMIC:
> +          pos = __lseek (fd, ph->p_offset, SEEK_SET);

Same comment as before regarding non-LFS interfaces.

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

Other occurrences on loader code does not handle partial read, so I think
it would be better to follow current practice.  Also use __pread64_nocancel
instead, it allows to remove the two __lseek calls.  


> +
> +              switch (entry.d_tag)
> +                {
> +                case DT_GNU_FLAGS_1:
> +                  unique = entry.d_un.d_val & DF_GNU_1_UNIQUE;

Add a /* fallthrough */ comment here.  I will send a patch to add the
FALLTHROUGH macro to at least on internal headers (and my on cdefs.h)
so we might use instead of the multiple different comment variants used
by  -Wimplicit-fallthrough. 

> +                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 unique;
> +}
>  
>  /* Process PT_GNU_PROPERTY program header PH in module L after
>     PT_LOAD segments are mapped.  Only one NT_GNU_PROPERTY_TYPE_0
> @@ -1098,6 +1154,32 @@ _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 lose_errno;
> +	}
> +    }
> +
> +  /* We need to check for DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE before we start
> +     initialising any namespace dependent metatada.  */
> +  if (nsid != LM_ID_BASE)
> +    {
> +      /* 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

Double space after period.

> +         the target nsid.  */
> +      if (_has_gnu_unique (fd, header, phdr))
> +        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))
> @@ -1115,20 +1197,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 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.  */
> 

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

* Re: [RFC][PATCH v8 15/20] Suppress audit calls when a (new) namespace is empty
  2021-02-09 17:18 ` [RFC][PATCH v8 15/20] Suppress audit calls when a (new) namespace is empty Vivek Das Mohapatra via Libc-alpha
@ 2021-02-19 19:45   ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-19 19:45 UTC (permalink / raw
  To: Vivek Das Mohapatra, libc-alpha



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> When preparing an RTLD_SHARED proxy in a new namespace
> it is possible for the target namespace to be empty:
> 
> This can happen for RTLD_SHARED + LM_ID_NEWLM.
> 
> The audit infrastructure should not be invoked at this
> point (as there's nothing there to audit yet).
> ---
>  elf/dl-load.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/elf/dl-load.c b/elf/dl-load.c
> index 13879af82c..4e8e7ca031 100644
> --- a/elf/dl-load.c
> +++ b/elf/dl-load.c
> @@ -1127,8 +1127,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
>  	  && __glibc_unlikely (GLRO(dl_naudit) > 0))
>  	{
>  	  struct link_map *head = GL(dl_ns)[nsid]._ns_loaded;
> -	  /* Do not call the functions for any auditing object.  */
> -	  if (head->l_auditing == 0)
> +	  /* Do not call the functions for any auditing object.
> +	     Do not try to call auditing functions if the namespace
> +	     is currently empty. This can hapen when opening the first
> +	     DSO in a new namespace.  */
> +	  if (head && head->l_auditing == 0)

No implicit checks.

>  	    {
>  	      struct audit_ifaces *afct = GLRO(dl_audit);
>  	      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
> 

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

* Re: [RFC][PATCH v8 12/20] Use the new DSO finder helper function since we have it
  2021-02-19 14:39   ` Adhemerval Zanella via Libc-alpha
@ 2021-02-19 19:50     ` Adhemerval Zanella via Libc-alpha
  2021-02-22 18:44     ` Vivek Das Mohapatra via Libc-alpha
  1 sibling, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-19 19:50 UTC (permalink / raw
  To: libc-alpha, Vivek Das Mohapatra



On 19/02/2021 11:39, Adhemerval Zanella wrote:
> 
> 
> On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
>> ---
>>  elf/dl-load.c | 43 +++++++++++++++++--------------------------
>>  1 file changed, 17 insertions(+), 26 deletions(-)
>>
>> diff --git a/elf/dl-load.c b/elf/dl-load.c
>> index 780bca99e8..13ac2053b8 100644
>> --- a/elf/dl-load.c
>> +++ b/elf/dl-load.c
>> @@ -2133,35 +2133,26 @@ _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)
>> +  l = _dl_find_dso (name, nsid);
>> +
>> +  if (l != NULL)
>>      {
>> -      /* 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.  */
>> +#ifdef SHARED
>> +      /* If we are trying to load a DF_GNU_1_UNIQUE flagged DSO which WAS
>> +         already opened in the target NS but with RTLD_ISOLATE so it WAS NOT
>> +         created as a proxy we need to error out since we cannot satisfy the
>> +         DF_GNU_1_UNIQUE is-equivalent-to RTLD_SHARED semantics.  */
>> +      if (!(mode & RTLD_ISOLATE) &&

Also the new RTLD_ISOLATE flag is only defined later in this set.

>> +          (l->l_ns != LM_ID_BASE) &&
>> +          (l->l_gnu_flags_1 & DF_GNU_1_UNIQUE) &&
>> +          !l->l_proxy)
>> +      {
>> +        _dl_signal_error (EEXIST, name, NULL,
>> +                          N_("object cannot be demoted to a proxy"));
>> +      }
>> +#endif
>>        return l;
> 
> I think this patch should reorganized along with the previous, where
> first you refactor the code to use find_dso and *then* add the
> required l_proxy change in a subsequent patch.
> 
> (There are other patch organization that I think should be changed,
> I will get back to them once I finish reviewing the set)
> 
>>      }
>> -
> 
> I usually avoid such spurious change.
> 
>>    /* Display information if we are debugging.  */
>>    if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)
>>        && loader != NULL)
>>

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

* Re: [RFC][PATCH v8 16/20] Suppress inter-namespace DSO sharing for audit libraries
  2021-02-09 17:18 ` [RFC][PATCH v8 16/20] Suppress inter-namespace DSO sharing for audit libraries Vivek Das Mohapatra via Libc-alpha
@ 2021-02-19 20:39   ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-19 20:39 UTC (permalink / raw
  To: Vivek Das Mohapatra, libc-alpha



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> Audit libraries should not participate in DSO sharing: In
> particular libraries tagged with DF_GNU_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 the RTLD_ISOLATE
> flag from the relevant entry point in the dl modes argument.
> ---
>  bits/dlfcn.h              |  3 +++
>  elf/dl-load.c             |  5 +++--
>  elf/dl-open.c             | 13 +++++++++++--
>  elf/rtld.c                |  2 +-
>  sysdeps/mips/bits/dlfcn.h |  3 +++
>  5 files changed, 21 insertions(+), 5 deletions(-)
> 
> diff --git a/bits/dlfcn.h b/bits/dlfcn.h
> index 0daa789693..f910528b32 100644
> --- a/bits/dlfcn.h
> +++ b/bits/dlfcn.h
> @@ -32,6 +32,9 @@
>     visible as if the object were linked directly into the program.  */
>  #define RTLD_GLOBAL	0x00100
>  
> +/* Suppress RTLD_SHARED and/or DF_GNU_1_UNIQUE.  */
> +#define RTLD_ISOLATE 0x00040
> +
>  /* 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

Ok, the idea is to export the new flag to userpace.

> diff --git a/elf/dl-load.c b/elf/dl-load.c
> index 4e8e7ca031..44fd3b5489 100644
> --- a/elf/dl-load.c
> +++ b/elf/dl-load.c
> @@ -1079,7 +1079,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
>    /* DSOs in the main namespace which are flagged DF_GNU_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)
> @@ -1174,7 +1174,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
>  
>    /* We need to check for DT_GNU_FLAGS_1/DF_GNU_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)))
>      {
>        /* 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

Ok.

> @@ -2188,6 +2188,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 38b3587d4a..d3c3e32be2 100644
> --- a/elf/dl-open.c
> +++ b/elf/dl-open.c
> @@ -485,9 +485,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;

Use 'bool' here.

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

Indentation seems off here (4 space instead of 2).

>    /* 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
> @@ -539,6 +546,7 @@ dl_open_worker (void *a)
>       mode and set 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);
> @@ -650,7 +658,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.  */

Ok.

>    for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
> diff --git a/elf/rtld.c b/elf/rtld.c
> index 596b6ac3d9..82069658b3 100644
> --- a/elf/rtld.c
> +++ b/elf/rtld.c
> @@ -659,7 +659,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/sysdeps/mips/bits/dlfcn.h b/sysdeps/mips/bits/dlfcn.h
> index 1331771a17..a0a35bba5d 100644
> --- a/sysdeps/mips/bits/dlfcn.h
> +++ b/sysdeps/mips/bits/dlfcn.h
> @@ -39,6 +39,9 @@
>     share a single instance of a DSO.  */
>  #define RTLD_SHARED 0x00020
>  
> +/* Suppress RTLD_SHARED and/or DF_GNU_1_UNIQUE.  */
> +#define RTLD_ISOLATE 0x00040
> +
>  /* 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.  */
> 

Ok.

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

* Re: [RFC][PATCH v8 12/20] Use the new DSO finder helper function since we have it
  2021-02-19 14:39   ` Adhemerval Zanella via Libc-alpha
  2021-02-19 19:50     ` Adhemerval Zanella via Libc-alpha
@ 2021-02-22 18:44     ` Vivek Das Mohapatra via Libc-alpha
  2021-02-22 18:51       ` Adhemerval Zanella via Libc-alpha
  1 sibling, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-22 18:44 UTC (permalink / raw
  To: Adhemerval Zanella; +Cc: libc-alpha

> I think this patch should reorganized along with the previous, where
> first you refactor the code to use find_dso and *then* add the
> required l_proxy change in a subsequent patch.

Do you want this combined with the preceding patch or reorganised
in some other way?


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

* Re: [RFC][PATCH v8 12/20] Use the new DSO finder helper function since we have it
  2021-02-22 18:44     ` Vivek Das Mohapatra via Libc-alpha
@ 2021-02-22 18:51       ` Adhemerval Zanella via Libc-alpha
  2021-02-22 23:50         ` Vivek Das Mohapatra via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-22 18:51 UTC (permalink / raw
  To: Vivek Das Mohapatra; +Cc: libc-alpha



On 22/02/2021 15:44, Vivek Das Mohapatra wrote:
>> I think this patch should reorganized along with the previous, where
>> first you refactor the code to use find_dso and *then* add the
>> required l_proxy change in a subsequent patch.
> 
> Do you want this combined with the preceding patch or reorganised
> in some other way?
> 

My plan is to finish the review and send a overall note of how I
think the set should be better organized.

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

* Re: [RFC][PATCH v8 17/20] dlsym, dlvsym should be able to look up symbols via DSO proxies
  2021-02-09 17:18 ` [RFC][PATCH v8 17/20] dlsym, dlvsym should be able to look up symbols via DSO proxies Vivek Das Mohapatra via Libc-alpha
@ 2021-02-22 18:51   ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-22 18:51 UTC (permalink / raw
  To: libc-alpha



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> ---
>  elf/dl-sym.c | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
> 
> diff --git a/elf/dl-sym.c b/elf/dl-sym.c
> index dfd6169e12..b7252804ad 100644
> --- a/elf/dl-sym.c
> +++ b/elf/dl-sym.c
> @@ -96,6 +96,10 @@ do_sym (void *handle, const char *name, void *who,
>      {
>        match = _dl_sym_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

Ok.

> @@ -140,6 +144,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;
>  

Ok.

> @@ -150,6 +159,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);
>      }
> 

Ok.

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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-09 17:18 ` [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs Vivek Das Mohapatra via Libc-alpha
@ 2021-02-22 20:39   ` Adhemerval Zanella via Libc-alpha
  2021-02-22 21:19     ` Florian Weimer via Libc-alpha
  2021-02-23  0:17     ` Vivek Das Mohapatra via Libc-alpha
  0 siblings, 2 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-22 20:39 UTC (permalink / raw
  To: Vivek Das Mohapatra, libc-alpha



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> libc.so, libpthread.so etc should have the new unique-dso-by-default
> flag set to allow dlmopen to work better (libc et al instance shared
> by default when DSOs dlmopened into a new namespace).

The DT_GNU_FLAGS_1 and -z,unique was added on binutils 2.36 (commit
6a0a0dd0cc437) and glibc currently only requires binutils 2.25.  It
means that glibc built with an older binutils won't set 
DF_GNU_1_UNIQUE for its own DSOs.

If I understood correctly, it means that libc.so and glibc libraries
won't really work on shared mode (dlmopen a library with DT_SHARED)
as indicated by the failures using the own set tests with a binutils
2.35:

FAIL: elf/tst-dlmopen-rtld-audit-unique1
FAIL: elf/tst-dlmopen-rtld-audit-unique3
FAIL: elf/tst-dlmopen-rtld-audit-unique6
FAIL: elf/tst-dlmopen-rtld-unique1
FAIL: elf/tst-dlmopen-rtld-unique3
FAIL: elf/tst-dlmopen-rtld-unique6

Since DF_GNU_1_UNIQUE is not supported, the namespace value is not the
expected one. So I think this support is required to avoid having a 
broken/incomplete support (where glibc dlmopen accepts the newer flags, 
but glibc shared libraries themselves do not support DF_GNU_1_UNIQUE).

We have some options to fix it:

  1. Bump the minimum supported binutils version to 2.36. It would be
     a large change, since we usually do incremental changes over releases
     (the binutils 2.25 change from 2.22 was done on glibc 2.26).

  2. Add a configure check and enable RTLD_SHARED iff ld supports
     -z unique.  It would require return EINVAL is RTLD_SHARED or
     RTLD_ISOLATE if the configure check see the binutils do not
     support it (and extend the check for the tests to return
     UNSUPPORTED in such case).

  3. Find a way to force add DF_GNU_1_UNIQUE on older binutils
     (since its support is just a dynamic section existence)

The 1. is simple but will force a large upgrade bump in toolchain for 
users (although it might also allow some further cleanups).  I would like
to avoid it, but I won't oppose if there is no easy solution.

The 2. would require add some internal support (to avoid running tests
if ld does not provide support and add ifdef over loader code to ignore
DF_GNU_1_UNIQUE) and make glibc supports a dmopen based on configure support
(not ideal). 

The 3. is a hackery solution, but might work without incurring a toolchain
requirement bump (however I am not this is a easy solution).

Thoughts?


> ---
>  Makeconfig         | 1 +
>  Makerules          | 2 +-
>  htl/Makefile       | 2 +-
>  iconvdata/Makefile | 1 +
>  nptl/Makefile      | 2 +-
>  5 files changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/Makeconfig b/Makeconfig
> index 0a4811b5e5..d0e52f26fd 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 ca9885436e..82adffdc27 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/htl/Makefile b/htl/Makefile
> index c15c1b194e..5d0d76d941 100644
> --- a/htl/Makefile
> +++ b/htl/Makefile
> @@ -204,7 +204,7 @@ $(inst_libdir)/libpthread_syms.a: $(srcdir)/libpthread_syms.a $(+force)
>  libc-link.so = $(common-objpfx)libc.so
>  
>  extra-B-pthread.so = -B$(common-objpfx)htl/
> -LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst
> +LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,unique,-z,nodelete,-z,initfirst
>  
>  include ../Rules
>  
> diff --git a/iconvdata/Makefile b/iconvdata/Makefile
> index 55c527a5f7..ea5565eb40 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 8fb7fee6db..9090b88dec 100644
> --- a/nptl/Makefile
> +++ b/nptl/Makefile
> @@ -349,7 +349,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,unique,-z,nodelete,-z,initfirst
>  
>  tests += tst-cancelx7 tst-cancelx17 tst-cleanupx4
>  
> 

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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-22 20:39   ` Adhemerval Zanella via Libc-alpha
@ 2021-02-22 21:19     ` Florian Weimer via Libc-alpha
  2021-02-22 21:53       ` Adhemerval Zanella via Libc-alpha
  2021-02-23  0:17     ` Vivek Das Mohapatra via Libc-alpha
  1 sibling, 1 reply; 78+ messages in thread
From: Florian Weimer via Libc-alpha @ 2021-02-22 21:19 UTC (permalink / raw
  To: Adhemerval Zanella via Libc-alpha

* Adhemerval Zanella via Libc-alpha:

> We have some options to fix it:
>
>   1. Bump the minimum supported binutils version to 2.36. It would be
>      a large change, since we usually do incremental changes over releases
>      (the binutils 2.25 change from 2.22 was done on glibc 2.26).
>
>   2. Add a configure check and enable RTLD_SHARED iff ld supports
>      -z unique.  It would require return EINVAL is RTLD_SHARED or
>      RTLD_ISOLATE if the configure check see the binutils do not
>      support it (and extend the check for the tests to return
>      UNSUPPORTED in such case).
>
>   3. Find a way to force add DF_GNU_1_UNIQUE on older binutils
>      (since its support is just a dynamic section existence)

(1) is fine, I think.  Moving from 2.25 (2015) to 2.26 (2016) isn't that
big of a change.

> The 3. is a hackery solution, but might work without incurring a toolchain
> requirement bump (however I am not this is a easy solution).

There's a thread about this:

  Creating arbitrary dynamic tags with BFD ld
  <https://sourceware.org/legacy-ml/binutils/2019-09/msg00285.html>
  <https://sourceware.org/legacy-ml/binutils/2019-09/msg00287.html>

(Search machine indexing of sourceware.org mailing lists is really poor
these days unfortunately.)

Thanks,
Florian


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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-22 21:19     ` Florian Weimer via Libc-alpha
@ 2021-02-22 21:53       ` Adhemerval Zanella via Libc-alpha
  2021-02-23  3:26         ` Alan Modra via Libc-alpha
  2021-02-23 10:00         ` Florian Weimer via Libc-alpha
  0 siblings, 2 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-22 21:53 UTC (permalink / raw
  To: Florian Weimer, Adhemerval Zanella via Libc-alpha; +Cc: Alan Modra



On 22/02/2021 18:19, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
> 
>> We have some options to fix it:
>>
>>   1. Bump the minimum supported binutils version to 2.36. It would be
>>      a large change, since we usually do incremental changes over releases
>>      (the binutils 2.25 change from 2.22 was done on glibc 2.26).
>>
>>   2. Add a configure check and enable RTLD_SHARED iff ld supports
>>      -z unique.  It would require return EINVAL is RTLD_SHARED or
>>      RTLD_ISOLATE if the configure check see the binutils do not
>>      support it (and extend the check for the tests to return
>>      UNSUPPORTED in such case).
>>
>>   3. Find a way to force add DF_GNU_1_UNIQUE on older binutils
>>      (since its support is just a dynamic section existence)
> 
> (1) is fine, I think.  Moving from 2.25 (2015) to 2.26 (2016) isn't that
> big of a change.

It is not to 2.26, but rather *2.36* (2021).

> 
>> The 3. is a hackery solution, but might work without incurring a toolchain
>> requirement bump (however I am not this is a easy solution).
> 
> There's a thread about this:
> 
>   Creating arbitrary dynamic tags with BFD ld
>   <https://sourceware.org/legacy-ml/binutils/2019-09/msg00285.html>
>   <https://sourceware.org/legacy-ml/binutils/2019-09/msg00287.html>
> 
> (Search machine indexing of sourceware.org mailing lists is really poor
> these days unfortunately.)

Interesting, but I can't get this to work.  I added an object:

$ cat elf/dynamic-notes.S 
#define DT_GNU_FLAGS_1   0x6ffffdf4
#define DF_GNU_1_UNIQUE  0x00000001

.section .dynamic, "a", %6
.dc.a   DT_GNU_FLAGS_1
.dc.a   DF_GNU_1_UNIQUE

And added a rule to just build it:

diff --git a/elf/Makefile b/elf/Makefile
index bccf31b1a9..d244ba79b3 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -105,7 +105,7 @@ ld-map              = $(common-objpfx)ld.map
 endif
 
 ifeq (yes,$(build-shared))
-extra-objs     = $(all-rtld-routines:%=%.os) sofini.os interp.os
+extra-objs     = $(all-rtld-routines:%=%.os) sofini.os interp.os dynamic-notes.os
 generated      += librtld.os dl-allobjs.os ld.so ldd
 install-others = $(inst_rtlddir)/$(rtld-installed-name)
 install-bin-script = ldd

And edit the shlib.lds manually:

$ grep dynamic shlib.lds 
  .dynamic        : { *dynamic-notes.os(.dynamic) *(.dynamic) }

But I can get a GNU_FLAGS_1 entry on dynamic sections.

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

* Re: [RFC][PATCH v8 12/20] Use the new DSO finder helper function since we have it
  2021-02-22 18:51       ` Adhemerval Zanella via Libc-alpha
@ 2021-02-22 23:50         ` Vivek Das Mohapatra via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-22 23:50 UTC (permalink / raw
  To: Adhemerval Zanella; +Cc: libc-alpha

>> Do you want this combined with the preceding patch or reorganised
>> in some other way?
>
> My plan is to finish the review and send a overall note of how I think the set 
> should be better organized.

Ok, thanks.


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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-22 20:39   ` Adhemerval Zanella via Libc-alpha
  2021-02-22 21:19     ` Florian Weimer via Libc-alpha
@ 2021-02-23  0:17     ` Vivek Das Mohapatra via Libc-alpha
  2021-02-23 12:02       ` Adhemerval Zanella via Libc-alpha
  1 sibling, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-23  0:17 UTC (permalink / raw
  To: Adhemerval Zanella; +Cc: libc-alpha

> We have some options to fix it:
>
>  1. Bump the minimum supported binutils version to 2.36. It would be
>     a large change, since we usually do incremental changes over releases

It's a large bump: OTOH is it the case that people are going to be
rolling out cutting edge glibc with old binutils? (Serious question,
the answer might be yes in whic case we do need to think about this).

>  2. Add a configure check and enable RTLD_SHARED iff ld supports
>     -z unique.  It would require return EINVAL is RTLD_SHARED or

Doable, but then we'd have glibc at the same version with different
capabilities/behaviours in the linker: Asking for pain imo.

>  3. Find a way to force add DF_GNU_1_UNIQUE on older binutils
>     (since its support is just a dynamic section existence)

I think this is doable, either with a linker script or by
using the spare dynamic tags added by ld (cf --spare-dynamic-sections)
and writing in the value we want in the first spare slot.

I'll have a look at adding this since it enables the feature with
minimal friction for distributions/users/etc.


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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-22 21:53       ` Adhemerval Zanella via Libc-alpha
@ 2021-02-23  3:26         ` Alan Modra via Libc-alpha
  2021-02-23 11:57           ` Adhemerval Zanella via Libc-alpha
  2021-02-23 10:00         ` Florian Weimer via Libc-alpha
  1 sibling, 1 reply; 78+ messages in thread
From: Alan Modra via Libc-alpha @ 2021-02-23  3:26 UTC (permalink / raw
  To: Adhemerval Zanella; +Cc: Florian Weimer, Adhemerval Zanella via Libc-alpha

On Mon, Feb 22, 2021 at 06:53:07PM -0300, Adhemerval Zanella wrote:
> $ grep dynamic shlib.lds 
>   .dynamic        : { *dynamic-notes.os(.dynamic) *(.dynamic) }
> 
> But I can get a GNU_FLAGS_1 entry on dynamic sections.

I assume you meant "can't".  If you did get everything correct in your
script then the added user .dynamic should appear, and readelf will
show it.  However, _DYNAMIC will be defined at the start of the linker
generated .dynamic section.

If there was a problem in your script, then the user .dynamic section
is likely at the end of the linker generated .dynamic after a number
of DT_NULL entries.  readelf stops displaying at the first DT_NULL.
objdump -sj.dynamic to see.

-- 
Alan Modra
Australia Development Lab, IBM

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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-22 21:53       ` Adhemerval Zanella via Libc-alpha
  2021-02-23  3:26         ` Alan Modra via Libc-alpha
@ 2021-02-23 10:00         ` Florian Weimer via Libc-alpha
  2021-02-23 11:58           ` Adhemerval Zanella via Libc-alpha
  1 sibling, 1 reply; 78+ messages in thread
From: Florian Weimer via Libc-alpha @ 2021-02-23 10:00 UTC (permalink / raw
  To: Adhemerval Zanella; +Cc: Adhemerval Zanella via Libc-alpha, Alan Modra

* Adhemerval Zanella:

> On 22/02/2021 18:19, Florian Weimer wrote:
>> * Adhemerval Zanella via Libc-alpha:
>> 
>>> We have some options to fix it:
>>>
>>>   1. Bump the minimum supported binutils version to 2.36. It would be
>>>      a large change, since we usually do incremental changes over releases
>>>      (the binutils 2.25 change from 2.22 was done on glibc 2.26).
>>>
>>>   2. Add a configure check and enable RTLD_SHARED iff ld supports
>>>      -z unique.  It would require return EINVAL is RTLD_SHARED or
>>>      RTLD_ISOLATE if the configure check see the binutils do not
>>>      support it (and extend the check for the tests to return
>>>      UNSUPPORTED in such case).
>>>
>>>   3. Find a way to force add DF_GNU_1_UNIQUE on older binutils
>>>      (since its support is just a dynamic section existence)
>> 
>> (1) is fine, I think.  Moving from 2.25 (2015) to 2.26 (2016) isn't that
>> big of a change.
>
> It is not to 2.26, but rather *2.36* (2021).

Ugh, that's way too soon.

> But I can get a GNU_FLAGS_1 entry on dynamic sections.

Maybe we can rewrite the binaries after linking to add the flag if we
can't get BFD ld to produce it.

Thanks,
Florian


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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-23  3:26         ` Alan Modra via Libc-alpha
@ 2021-02-23 11:57           ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-23 11:57 UTC (permalink / raw
  To: Alan Modra; +Cc: Florian Weimer, Adhemerval Zanella via Libc-alpha



On 23/02/2021 00:26, Alan Modra wrote:
> On Mon, Feb 22, 2021 at 06:53:07PM -0300, Adhemerval Zanella wrote:
>> $ grep dynamic shlib.lds 
>>   .dynamic        : { *dynamic-notes.os(.dynamic) *(.dynamic) }
>>
>> But I can get a GNU_FLAGS_1 entry on dynamic sections.
> 
> I assume you meant "can't".  If you did get everything correct in your
> script then the added user .dynamic should appear, and readelf will
> show it.  However, _DYNAMIC will be defined at the start of the linker
> generated .dynamic section.
> 
> If there was a problem in your script, then the user .dynamic section
> is likely at the end of the linker generated .dynamic after a number
> of DT_NULL entries.  readelf stops displaying at the first DT_NULL.
> objdump -sj.dynamic to see.
> 

My mistake here Alan, sorry for the noise. I could get a the GNU_FLAGS_1
added with a proper modified linker script and with the object I referenced.

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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-23 10:00         ` Florian Weimer via Libc-alpha
@ 2021-02-23 11:58           ` Adhemerval Zanella via Libc-alpha
  2021-02-23 12:12             ` Florian Weimer via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-23 11:58 UTC (permalink / raw
  To: Florian Weimer; +Cc: Adhemerval Zanella via Libc-alpha, Alan Modra



On 23/02/2021 07:00, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>> On 22/02/2021 18:19, Florian Weimer wrote:
>>> * Adhemerval Zanella via Libc-alpha:
>>>
>>>> We have some options to fix it:
>>>>
>>>>   1. Bump the minimum supported binutils version to 2.36. It would be
>>>>      a large change, since we usually do incremental changes over releases
>>>>      (the binutils 2.25 change from 2.22 was done on glibc 2.26).
>>>>
>>>>   2. Add a configure check and enable RTLD_SHARED iff ld supports
>>>>      -z unique.  It would require return EINVAL is RTLD_SHARED or
>>>>      RTLD_ISOLATE if the configure check see the binutils do not
>>>>      support it (and extend the check for the tests to return
>>>>      UNSUPPORTED in such case).
>>>>
>>>>   3. Find a way to force add DF_GNU_1_UNIQUE on older binutils
>>>>      (since its support is just a dynamic section existence)
>>>
>>> (1) is fine, I think.  Moving from 2.25 (2015) to 2.26 (2016) isn't that
>>> big of a change.
>>
>> It is not to 2.26, but rather *2.36* (2021).
> 
> Ugh, that's way too soon.

Yeah, my take as well :/

> 
>> But I can get a GNU_FLAGS_1 entry on dynamic sections.
> 
> Maybe we can rewrite the binaries after linking to add the flag if we
> can't get BFD ld to produce it.

I didn't really checked my build environment, with some adjustment I 
could get the new dynamic section with Alan's trick.

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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-23  0:17     ` Vivek Das Mohapatra via Libc-alpha
@ 2021-02-23 12:02       ` Adhemerval Zanella via Libc-alpha
  2021-02-23 13:24         ` Adhemerval Zanella via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-23 12:02 UTC (permalink / raw
  To: Vivek Das Mohapatra; +Cc: libc-alpha



On 22/02/2021 21:17, Vivek Das Mohapatra wrote:
>> We have some options to fix it:
>>
>>  1. Bump the minimum supported binutils version to 2.36. It would be
>>     a large change, since we usually do incremental changes over releases
> 
> It's a large bump: OTOH is it the case that people are going to be
> rolling out cutting edge glibc with old binutils? (Serious question,
> the answer might be yes in whic case we do need to think about this).
> 
>>  2. Add a configure check and enable RTLD_SHARED iff ld supports
>>     -z unique.  It would require return EINVAL is RTLD_SHARED or
> 
> Doable, but then we'd have glibc at the same version with different
> capabilities/behaviours in the linker: Asking for pain imo.
> 
>>  3. Find a way to force add DF_GNU_1_UNIQUE on older binutils
>>     (since its support is just a dynamic section existence)
> 
> I think this is doable, either with a linker script or by
> using the spare dynamic tags added by ld (cf --spare-dynamic-sections)
> and writing in the value we want in the first spare slot.

In fact I now more inclined to use 3. now that I checked that Alan's
trick [1] does work.  The assembly file should be architecture
independent, so it is a matter of building, changing the shlib.lds
generation to add the new object and adding the new note on each required
library.

[1] https://sourceware.org/legacy-ml/binutils/2019-09/msg00287.html

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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-23 11:58           ` Adhemerval Zanella via Libc-alpha
@ 2021-02-23 12:12             ` Florian Weimer via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Florian Weimer via Libc-alpha @ 2021-02-23 12:12 UTC (permalink / raw
  To: Adhemerval Zanella; +Cc: Adhemerval Zanella via Libc-alpha, Alan Modra

* Adhemerval Zanella:

>>> But I can get a GNU_FLAGS_1 entry on dynamic sections.
>> 
>> Maybe we can rewrite the binaries after linking to add the flag if we
>> can't get BFD ld to produce it.
>
> I didn't really checked my build environment, with some adjustment I 
> could get the new dynamic section with Alan's trick.

This is good news, thanks for doing that experiment.

Florian


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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-23 12:02       ` Adhemerval Zanella via Libc-alpha
@ 2021-02-23 13:24         ` Adhemerval Zanella via Libc-alpha
  2021-02-23 18:46           ` Vivek Das Mohapatra via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-23 13:24 UTC (permalink / raw
  To: Vivek Das Mohapatra; +Cc: libc-alpha, Alan Modra



On 23/02/2021 09:02, Adhemerval Zanella wrote:
> 
> 
> On 22/02/2021 21:17, Vivek Das Mohapatra wrote:
>>> We have some options to fix it:
>>>
>>>  1. Bump the minimum supported binutils version to 2.36. It would be
>>>     a large change, since we usually do incremental changes over releases
>>
>> It's a large bump: OTOH is it the case that people are going to be
>> rolling out cutting edge glibc with old binutils? (Serious question,
>> the answer might be yes in whic case we do need to think about this).
>>
>>>  2. Add a configure check and enable RTLD_SHARED iff ld supports
>>>     -z unique.  It would require return EINVAL is RTLD_SHARED or
>>
>> Doable, but then we'd have glibc at the same version with different
>> capabilities/behaviours in the linker: Asking for pain imo.
>>
>>>  3. Find a way to force add DF_GNU_1_UNIQUE on older binutils
>>>     (since its support is just a dynamic section existence)
>>
>> I think this is doable, either with a linker script or by
>> using the spare dynamic tags added by ld (cf --spare-dynamic-sections)
>> and writing in the value we want in the first spare slot.
> 
> In fact I now more inclined to use 3. now that I checked that Alan's
> trick [1] does work.  The assembly file should be architecture
> independent, so it is a matter of building, changing the shlib.lds
> generation to add the new object and adding the new note on each required
> library.
> 
> [1] https://sourceware.org/legacy-ml/binutils/2019-09/msg00287.html
> 

This patch below based on your tree could get the dynamic note on libc.so.
It has to explicit add the dynamic-note.os as an extra object (adding an
extra object on libc.so build will add on libc_pic.{a,os} and linker script
won't handle).

The shlib.lds would require some work to get the previous '.dynamic'
info dumped from compiler. Also it does not add the dynamic section on
other libraries than libc.so.

Alan pointed me out that _DYNAMIC can be in the script too, but I am not
sure it would be simpler in our build process.  And dynamic-notes.c could
also be used to add other dynamic section when required.

---

diff --git a/Makerules b/Makerules
index 82adffdc27..fc6061e12d 100644
--- a/Makerules
+++ b/Makerules
@@ -581,7 +581,8 @@ $(common-objpfx)shlib.lds: $(common-objpfx)config.make $(..)Makerules
                 PROVIDE(__start___libc_IO_vtables = .);\
                 __libc_IO_vtables : { *(__libc_IO_vtables) }\
                 PROVIDE(__stop___libc_IO_vtables = .);\
-                /DISCARD/ : { *(.gnu.glibc-stub.*) }@'
+                /DISCARD/ : { *(.gnu.glibc-stub.*) }@' \
+             -e 's/^.*\*(\.dynamic).*$$/   .dynamic : { *dynamic-notes.os(.dynamic) *(.dynamic) }/'
        test -s $@T
        mv -f $@T $@
 common-generated += shlib.lds
@@ -693,6 +694,7 @@ $(common-objpfx)linkobj/libc.so: link-libc-deps = # empty
 $(common-objpfx)libc.so: $(common-objpfx)libc_pic.os$(libc_pic_clean) \
                         $(elf-objpfx)sofini.os \
                         $(elf-objpfx)interp.os \
+                        $(elf-objpfx)dynamic-notes.os \
                         $(elf-objpfx)ld.so \
                         $(shlib-lds)
        $(build-shlib)
diff --git a/elf/Makefile b/elf/Makefile
index bccf31b1a9..e3c5937caf 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -105,7 +105,8 @@ ld-map              = $(common-objpfx)ld.map
 endif
 
 ifeq (yes,$(build-shared))
-extra-objs     = $(all-rtld-routines:%=%.os) sofini.os interp.os
+extra-objs     = $(all-rtld-routines:%=%.os) sofini.os interp.os \
+                 dynamic-notes.os
 generated      += librtld.os dl-allobjs.os ld.so ldd
 install-others = $(inst_rtlddir)/$(rtld-installed-name)
 install-bin-script = ldd
diff --git a/elf/dynamic-notes.c b/elf/dynamic-notes.c
new file mode 100644
index 0000000000..d0b487e970
--- /dev/null
+++ b/elf/dynamic-notes.c
@@ -0,0 +1,4 @@
+#include <link.h>
+
+const ElfW(Dyn) __dynamic_note __attribute__ ((section (".dynamic"))) =
+  { .d_tag = DT_GNU_FLAGS_1, .d_un.d_val = DF_GNU_1_UNIQUE };


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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-23 13:24         ` Adhemerval Zanella via Libc-alpha
@ 2021-02-23 18:46           ` Vivek Das Mohapatra via Libc-alpha
  2021-02-23 18:48             ` Adhemerval Zanella via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Vivek Das Mohapatra via Libc-alpha @ 2021-02-23 18:46 UTC (permalink / raw
  To: Adhemerval Zanella; +Cc: libc-alpha

> This patch below based on your tree could get the dynamic note on libc.so.
> It has to explicit add the dynamic-note.os as an extra object (adding an
> extra object on libc.so build will add on libc_pic.{a,os} and linker script
> won't handle).

Thanks. Would you like this enabled for the necessary libraries
only when ld isn't new enough, or enabled unconditionally?


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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-23 18:46           ` Vivek Das Mohapatra via Libc-alpha
@ 2021-02-23 18:48             ` Adhemerval Zanella via Libc-alpha
  2021-02-23 19:01               ` Florian Weimer via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-23 18:48 UTC (permalink / raw
  To: Vivek Das Mohapatra; +Cc: libc-alpha



On 23/02/2021 15:46, Vivek Das Mohapatra wrote:
>> This patch below based on your tree could get the dynamic note on libc.so.
>> It has to explicit add the dynamic-note.os as an extra object (adding an
>> extra object on libc.so build will add on libc_pic.{a,os} and linker script
>> won't handle).
> 
> Thanks. Would you like this enabled for the necessary libraries
> only when ld isn't new enough, or enabled unconditionally?
> 

I think it would be simpler to just this scheme which is independently of
ld version instead of using -z,unique. We might clean this up once we
set the minimum binutils version to 2.36.

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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-23 18:48             ` Adhemerval Zanella via Libc-alpha
@ 2021-02-23 19:01               ` Florian Weimer via Libc-alpha
  2021-02-23 19:06                 ` Adhemerval Zanella via Libc-alpha
  0 siblings, 1 reply; 78+ messages in thread
From: Florian Weimer via Libc-alpha @ 2021-02-23 19:01 UTC (permalink / raw
  To: Adhemerval Zanella via Libc-alpha

* Adhemerval Zanella via Libc-alpha:

> On 23/02/2021 15:46, Vivek Das Mohapatra wrote:
>>> This patch below based on your tree could get the dynamic note on libc.so.
>>> It has to explicit add the dynamic-note.os as an extra object (adding an
>>> extra object on libc.so build will add on libc_pic.{a,os} and linker script
>>> won't handle).
>> 
>> Thanks. Would you like this enabled for the necessary libraries
>> only when ld isn't new enough, or enabled unconditionally?
>> 
>
> I think it would be simpler to just this scheme which is independently of
> ld version instead of using -z,unique. We might clean this up once we
> set the minimum binutils version to 2.36.

The downside of this scheme is that the injected values come first,
which may confuse some consumers (although it should not).  Using the
binutils option generates a more regular-looking dynamic segment.

Thanks,
Florian


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

* Re: [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
  2021-02-23 19:01               ` Florian Weimer via Libc-alpha
@ 2021-02-23 19:06                 ` Adhemerval Zanella via Libc-alpha
  0 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-23 19:06 UTC (permalink / raw
  To: Florian Weimer, Adhemerval Zanella via Libc-alpha



On 23/02/2021 16:01, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
> 
>> On 23/02/2021 15:46, Vivek Das Mohapatra wrote:
>>>> This patch below based on your tree could get the dynamic note on libc.so.
>>>> It has to explicit add the dynamic-note.os as an extra object (adding an
>>>> extra object on libc.so build will add on libc_pic.{a,os} and linker script
>>>> won't handle).
>>>
>>> Thanks. Would you like this enabled for the necessary libraries
>>> only when ld isn't new enough, or enabled unconditionally?
>>>
>>
>> I think it would be simpler to just this scheme which is independently of
>> ld version instead of using -z,unique. We might clean this up once we
>> set the minimum binutils version to 2.36.
> 
> The downside of this scheme is that the injected values come first,
> which may confuse some consumers (although it should not).  Using the
> binutils option generates a more regular-looking dynamic segment.
> 

My understanding is only the final NULL entry is really position
dependent in dynamic sections scheme.  Our internal parsing assumes
it, for instance on elf_get_dynamic_info; and I think it should be 
a fair assumption that all external usage takes this in consideration.

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

* Re: [RFC][PATCH v8 19/20] Add dlmopen / RTLD_SHARED tests
  2021-02-09 17:18 ` [RFC][PATCH v8 19/20] Add dlmopen / RTLD_SHARED tests Vivek Das Mohapatra via Libc-alpha
@ 2021-02-26 19:50   ` Adhemerval Zanella via Libc-alpha
  2021-02-26 20:26   ` Andreas Schwab
  1 sibling, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-02-26 19:50 UTC (permalink / raw
  To: Vivek Das Mohapatra, libc-alpha



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> ---
>  elf/Makefile                         |   97 ++-
>  elf/tst-dlmopen-auditmod.c           |   23 +
>  elf/tst-dlmopen-common.h             |   33 +
>  elf/tst-dlmopen-main.h               | 1022 ++++++++++++++++++++++++++
>  elf/tst-dlmopen-modules.h            |   20 +
>  elf/tst-dlmopen-rtld-audit-shared1.c |   11 +
>  elf/tst-dlmopen-rtld-audit-shared2.c |   11 +
>  elf/tst-dlmopen-rtld-audit-shared3.c |   11 +
>  elf/tst-dlmopen-rtld-audit-shared4.c |   11 +
>  elf/tst-dlmopen-rtld-audit-shared5.c |   11 +
>  elf/tst-dlmopen-rtld-audit-shared6.c |   11 +
>  elf/tst-dlmopen-rtld-audit-unique1.c |   11 +
>  elf/tst-dlmopen-rtld-audit-unique2.c |   11 +
>  elf/tst-dlmopen-rtld-audit-unique3.c |   11 +
>  elf/tst-dlmopen-rtld-audit-unique4.c |   11 +
>  elf/tst-dlmopen-rtld-audit-unique5.c |   11 +
>  elf/tst-dlmopen-rtld-audit-unique6.c |   11 +
>  elf/tst-dlmopen-rtld-shared1.c       |   11 +
>  elf/tst-dlmopen-rtld-shared1.h       |   65 ++
>  elf/tst-dlmopen-rtld-shared2.c       |   11 +
>  elf/tst-dlmopen-rtld-shared2.h       |   67 ++
>  elf/tst-dlmopen-rtld-shared3.c       |   11 +
>  elf/tst-dlmopen-rtld-shared3.h       |   44 ++
>  elf/tst-dlmopen-rtld-shared4.c       |   11 +
>  elf/tst-dlmopen-rtld-shared4.h       |   15 +
>  elf/tst-dlmopen-rtld-shared5.c       |   11 +
>  elf/tst-dlmopen-rtld-shared5.h       |   26 +
>  elf/tst-dlmopen-rtld-shared6.c       |   11 +
>  elf/tst-dlmopen-rtld-shared6.h       |   37 +
>  elf/tst-dlmopen-rtld-unique1.c       |   11 +
>  elf/tst-dlmopen-rtld-unique1.h       |   87 +++
>  elf/tst-dlmopen-rtld-unique2.c       |   11 +
>  elf/tst-dlmopen-rtld-unique2.h       |   26 +
>  elf/tst-dlmopen-rtld-unique3.c       |   11 +
>  elf/tst-dlmopen-rtld-unique3.h       |   14 +
>  elf/tst-dlmopen-rtld-unique4.c       |   11 +
>  elf/tst-dlmopen-rtld-unique4.h       |   15 +
>  elf/tst-dlmopen-rtld-unique5.c       |   11 +
>  elf/tst-dlmopen-rtld-unique5.h       |   59 ++
>  elf/tst-dlmopen-rtld-unique6.c       |   11 +
>  elf/tst-dlmopen-rtld-unique6.h       |   52 ++
>  elf/tst-dlmopen-sharedmod-norm.c     |   11 +
>  elf/tst-dlmopen-sharedmod-uniq.c     |   11 +
>  elf/tst-dlmopen-std-do-test.h        |   11 +
>  44 files changed, 1998 insertions(+), 1 deletion(-)
>  create mode 100644 elf/tst-dlmopen-auditmod.c
>  create mode 100644 elf/tst-dlmopen-common.h
>  create mode 100644 elf/tst-dlmopen-main.h
>  create mode 100644 elf/tst-dlmopen-modules.h
>  create mode 100644 elf/tst-dlmopen-rtld-audit-shared1.c
>  create mode 100644 elf/tst-dlmopen-rtld-audit-shared2.c
>  create mode 100644 elf/tst-dlmopen-rtld-audit-shared3.c
>  create mode 100644 elf/tst-dlmopen-rtld-audit-shared4.c
>  create mode 100644 elf/tst-dlmopen-rtld-audit-shared5.c
>  create mode 100644 elf/tst-dlmopen-rtld-audit-shared6.c
>  create mode 100644 elf/tst-dlmopen-rtld-audit-unique1.c
>  create mode 100644 elf/tst-dlmopen-rtld-audit-unique2.c
>  create mode 100644 elf/tst-dlmopen-rtld-audit-unique3.c
>  create mode 100644 elf/tst-dlmopen-rtld-audit-unique4.c
>  create mode 100644 elf/tst-dlmopen-rtld-audit-unique5.c
>  create mode 100644 elf/tst-dlmopen-rtld-audit-unique6.c
>  create mode 100644 elf/tst-dlmopen-rtld-shared1.c
>  create mode 100644 elf/tst-dlmopen-rtld-shared1.h
>  create mode 100644 elf/tst-dlmopen-rtld-shared2.c
>  create mode 100644 elf/tst-dlmopen-rtld-shared2.h
>  create mode 100644 elf/tst-dlmopen-rtld-shared3.c
>  create mode 100644 elf/tst-dlmopen-rtld-shared3.h
>  create mode 100644 elf/tst-dlmopen-rtld-shared4.c
>  create mode 100644 elf/tst-dlmopen-rtld-shared4.h
>  create mode 100644 elf/tst-dlmopen-rtld-shared5.c
>  create mode 100644 elf/tst-dlmopen-rtld-shared5.h
>  create mode 100644 elf/tst-dlmopen-rtld-shared6.c
>  create mode 100644 elf/tst-dlmopen-rtld-shared6.h
>  create mode 100644 elf/tst-dlmopen-rtld-unique1.c
>  create mode 100644 elf/tst-dlmopen-rtld-unique1.h
>  create mode 100644 elf/tst-dlmopen-rtld-unique2.c
>  create mode 100644 elf/tst-dlmopen-rtld-unique2.h
>  create mode 100644 elf/tst-dlmopen-rtld-unique3.c
>  create mode 100644 elf/tst-dlmopen-rtld-unique3.h
>  create mode 100644 elf/tst-dlmopen-rtld-unique4.c
>  create mode 100644 elf/tst-dlmopen-rtld-unique4.h
>  create mode 100644 elf/tst-dlmopen-rtld-unique5.c
>  create mode 100644 elf/tst-dlmopen-rtld-unique5.h
>  create mode 100644 elf/tst-dlmopen-rtld-unique6.c
>  create mode 100644 elf/tst-dlmopen-rtld-unique6.h
>  create mode 100644 elf/tst-dlmopen-sharedmod-norm.c
>  create mode 100644 elf/tst-dlmopen-sharedmod-uniq.c
>  create mode 100644 elf/tst-dlmopen-std-do-test.h
> 
> diff --git a/elf/Makefile b/elf/Makefile
> index 16c89b6d07..bccf31b1a9 100644
> --- a/elf/Makefile
> +++ b/elf/Makefile
> @@ -196,6 +196,38 @@ static-dlopen-environment = \
>  tst-tls9-static-ENV = $(static-dlopen-environment)
>  tst-single_threaded-static-dlopen-ENV = $(static-dlopen-environment)
>  
> +dlmopen-rtld-tests-norm := \
> +	 tst-dlmopen-rtld-shared1 \
> +	 tst-dlmopen-rtld-shared2 \
> +	 tst-dlmopen-rtld-shared3 \
> +	 tst-dlmopen-rtld-shared4 \
> +	 tst-dlmopen-rtld-shared5 \
> +	 tst-dlmopen-rtld-shared6
> +

Ok, default RTLD_SHARED tests.

> +dlmopen-rtld-tests-uniq := \
> +	 tst-dlmopen-rtld-unique1 \
> +	 tst-dlmopen-rtld-unique2 \
> +	 tst-dlmopen-rtld-unique3 \
> +	 tst-dlmopen-rtld-unique4 \
> +	 tst-dlmopen-rtld-unique5 \
> +	 tst-dlmopen-rtld-unique6

Ok.  The main difference between the rtld-shared and rtld-unique tests
is the usage of DSO_INIQUE instead of DSO_NORMAL which is used on second
argument for dlmopen.

> +
> +dlmopen-rtld-audit-tests-norm := \
> +	 tst-dlmopen-rtld-audit-shared1 \
> +	 tst-dlmopen-rtld-audit-shared2 \
> +	 tst-dlmopen-rtld-audit-shared3 \
> +	 tst-dlmopen-rtld-audit-shared4 \
> +	 tst-dlmopen-rtld-audit-shared5 \
> +	 tst-dlmopen-rtld-audit-shared6

Ok.  The main difference between the rtld-shared and rtld-audir tests
is the new expected ns is different (EXPECTED_NS).


> +
> +dlmopen-rtld-audit-tests-uniq := \
> +	 tst-dlmopen-rtld-audit-unique1 \
> +	 tst-dlmopen-rtld-audit-unique2 \
> +	 tst-dlmopen-rtld-audit-unique3 \
> +	 tst-dlmopen-rtld-audit-unique4 \
> +	 tst-dlmopen-rtld-audit-unique5 \
> +	 tst-dlmopen-rtld-audit-unique6
> +

Ok.  The main difference between the rtld-unique and rtld-audit-unique
tests is the usage of DSO_INIQUE instead of DSO_NORMAL which is used on
seconda argument for dlmopen.


>  tests += restest1 preloadtest loadfail multiload origtest resolvfail \
>  	 constload1 order noload filter \
>  	 reldep reldep2 reldep3 reldep4 nodelete nodelete2 \
> @@ -225,7 +257,11 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
>  	 tst-audit14 tst-audit15 tst-audit16 \
>  	 tst-single_threaded tst-single_threaded-pthread \
>  	 tst-tls-ie tst-tls-ie-dlmopen argv0test \
> -	 tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask
> +	 tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \
> +	 $(dlmopen-rtld-tests-norm) \
> +	 $(dlmopen-rtld-tests-uniq) \
> +	 $(dlmopen-rtld-audit-tests-norm) \
> +	 $(dlmopen-rtld-audit-tests-uniq)
>  #	 reldep9
>  tests-internal += loadtest unload unload2 circleload1 \
>  	 neededtest neededtest2 neededtest3 neededtest4 \

Ok.

> @@ -286,6 +322,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
>  		$(modules-execstack-$(have-z-execstack)) \
>  		tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 \
>  		tst-dlmopen1mod tst-auditmod1 \
> +		tst-dlmopen-sharedmod-norm \
> +		tst-dlmopen-sharedmod-uniq \
> +		tst-dlmopen-auditmod \
>  		unload3mod1 unload3mod2 unload3mod3 unload3mod4 \
>  		unload4mod1 unload4mod2 unload4mod3 unload4mod4 \
>  		unload6mod1 unload6mod2 unload6mod3 \
> @@ -325,6 +364,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
>  		tst-tlsalign-lib tst-nodelete-opened-lib tst-nodelete2mod \
>  		tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \
>  		tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \
> +		tst-dlmopen-auditmod \
>  		tst-latepthreadmod $(tst-tls-many-dynamic-modules) \
>  		tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \
>  		tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \

Ok.

> @@ -823,6 +863,9 @@ tst-nodelete-uniquemod.so-no-z-defs = yes
>  tst-nodelete-rtldmod.so-no-z-defs = yes
>  tst-nodelete-zmod.so-no-z-defs = yes
>  tst-nodelete2mod.so-no-z-defs = yes
> +tst-dlmopen-sharedmod-norm.so-no-z-defs = yes
> +tst-dlmopen-sharedmod-uniq.so-no-z-defs = yes
> +tst-dlmopen-auditmod.so-no-z-defs = yes
>  
>  ifeq ($(build-shared),yes)
>  # Build all the modules even when not actually running test programs.
> @@ -1301,6 +1344,58 @@ $(objpfx)tst-dlmopen2.out: $(objpfx)tst-dlmopen1mod.so
>  $(objpfx)tst-dlmopen3: $(libdl)
>  $(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
>  
> +LDFLAGS-tst-dlmopen-sharedmod-uniq.so = -Wl,-z,unique

It incur in the same binutils support noted in the
'DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag' patch.  So if the idea
to to with the trick to add the required dynamic section with the trick of
using the linker script, we will need to use it here as well.

The only issue is it probably also require to add a new rule to create a
specific linker script to shared object tests (to add the .dynamic {}
trick).

> +$(objpfx)tst-dlmopen-sharedmod-norm.so: $(libdl)
> +$(objpfx)tst-dlmopen-sharedmod-uniq.so: $(libdl)
> +$(objpfx)tst-dlmopen-auditmod.so: $(libdl)
> +
> +dlmopen-rtld-tests-norm-executables := \
> +	 $(foreach x,$(dlmopen-rtld-tests-norm),$(objpfx)$(x))
> +dlmopen-rtld-tests-norm-out := \
> +	 $(foreach x,$(dlmopen-rtld-tests-norm),$(objpfx)$(x).out)
> +
> +dlmopen-rtld-tests-uniq-executables := \
> +	 $(foreach x,$(dlmopen-rtld-tests-uniq),$(objpfx)$(x))
> +dlmopen-rtld-tests-uniq-out := \
> +	 $(foreach x,$(dlmopen-rtld-tests-uniq),$(objpfx)$(x).out)
> +
> +dlmopen-rtld-audit-tests-norm-executables := \
> +	 $(foreach x,$(dlmopen-rtld-audit-tests-norm),$(objpfx)$(x))
> +dlmopen-rtld-audit-tests-norm-out := \
> +	 $(foreach x,$(dlmopen-rtld-audit-tests-norm),$(objpfx)$(x).out)
> +
> +dlmopen-rtld-audit-tests-uniq-executables := \
> +	 $(foreach x,$(dlmopen-rtld-audit-tests-uniq),$(objpfx)$(x))
> +dlmopen-rtld-audit-tests-uniq-out := \
> +	 $(foreach x,$(dlmopen-rtld-audit-tests-uniq),$(objpfx)$(x).out)
> +
> +$(dlmopen-rtld-tests-norm-executables): $(libdl)
> +$(dlmopen-rtld-tests-norm-out): $(objpfx)tst-dlmopen-sharedmod-norm.so
> +
> +$(dlmopen-rtld-tests-uniq-executables): $(libdl)
> +$(dlmopen-rtld-tests-uniq-out): $(objpfx)tst-dlmopen-sharedmod-uniq.so
> +
> +
> +$(dlmopen-rtld-audit-tests-norm-executables): $(libdl)
> +$(dlmopen-rtld-audit-tests-norm-out): $(objpfx)tst-dlmopen-sharedmod-norm.so
> +$(dlmopen-rtld-audit-tests-norm-out): $(objpfx)tst-dlmopen-auditmod.so
> +tst-dlmopen-rtld-audit-shared1-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
> +tst-dlmopen-rtld-audit-shared2-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
> +tst-dlmopen-rtld-audit-shared3-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
> +tst-dlmopen-rtld-audit-shared4-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
> +tst-dlmopen-rtld-audit-shared5-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
> +tst-dlmopen-rtld-audit-shared6-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
> +
> +$(dlmopen-rtld-audit-tests-uniq-executables): $(libdl)
> +$(dlmopen-rtld-audit-tests-uniq-out): $(objpfx)tst-dlmopen-sharedmod-uniq.so
> +$(dlmopen-rtld-audit-tests-uniq-out): $(objpfx)tst-dlmopen-auditmod.so
> +tst-dlmopen-rtld-audit-unique1-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
> +tst-dlmopen-rtld-audit-unique2-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
> +tst-dlmopen-rtld-audit-unique3-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
> +tst-dlmopen-rtld-audit-unique4-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
> +tst-dlmopen-rtld-audit-unique5-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
> +tst-dlmopen-rtld-audit-unique6-ENV = LD_AUDIT=$(objpfx)tst-dlmopen-auditmod.so
> +
>  $(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so
>  tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
>  

Ok.

> diff --git a/elf/tst-dlmopen-auditmod.c b/elf/tst-dlmopen-auditmod.c
> new file mode 100644
> index 0000000000..04457249d0
> --- /dev/null
> +++ b/elf/tst-dlmopen-auditmod.c
> @@ -0,0 +1,23 @@
> +/* Audit module for tst-dlmopen-rtld-audit-*
> +   Copyright © 2020 Free Software Foundation, Inc.

s/2020/2021

> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +unsigned int
> +la_version (unsigned int version)
> +{
> +  return version;
> +}

Ok

> diff --git a/elf/tst-dlmopen-common.h b/elf/tst-dlmopen-common.h
> new file mode 100644
> index 0000000000..5653c9c02c
> --- /dev/null
> +++ b/elf/tst-dlmopen-common.h
> @@ -0,0 +1,33 @@
> +#pragma once
> +

There is no other usage of pragma once and I don't see an impeding reason
to not use.  However I would prefer to go in a conservative way and use
include guards, I will send a email about the pragma once on libc-alpha
and see if there any impending reason to start adopt in more places.

Also, move the *after* the copyright header.

> +/* Common infrastructure for tst-dlmopen-rtld-*
> +   Copyright © 2020 Free Software Foundation, Inc.

s/2020/s2021

> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <gnu/lib-names.h>
> +
> +typedef struct
> +{
> +  const char *name;
> +  void *free;
> +} dlmopen_testresult;
> +
> +typedef dlmopen_testresult * (*dlmopen_testfunc) (void);
> +

Extra new line.

> diff --git a/elf/tst-dlmopen-main.h b/elf/tst-dlmopen-main.h
> new file mode 100644
> index 0000000000..2e091e9b8d
> --- /dev/null
> +++ b/elf/tst-dlmopen-main.h
> @@ -0,0 +1,1022 @@
> +#pragma once
> +

Same as before regarding 'pragma once'.

> +/* Main infrastructure for tst-dlmopen-rtld-*
> +   Copyright © 2020 Free Software Foundation, Inc.

s/2020/s2021

> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +/* dlmopen ± RTLD_SHARED/RTLD_ISOLATE semantics:

I would prefer to just use ascii, even on comments (s/±/+-).

> +
> +   RTLD_ISOLATE's purpose is to suppress all shared behaviour,
> +   mainly used fir LD_AUDIT code paths but available to the user

s/fir/for

> +   and also useful for constructing test case preconditions.
> +
> +   dlmopen should have the following behaviour:
> +
> +   Notation:
> +        Number of namespace (+ = make a new one in an empty NS)

Maybe use "'+' means make a new one in an empty NS" .

> +        |
> +     [+]X[p] - p indicates a proxy
> +      |
> +      + → new enry after the dlmopen call

s/→/->

> +
> +      Need to be able to inspect:
> +
> +      list of dl handles before we start (base state)
> +      list of dl handles after an action in each namespace
> +      ns of a given dl handle
> +      _real_ ns of a given handle (ie where does a proxy point)
> +
> +      Target is a normal DSO:
> +      Before | Target NS | RTLD Flags | After  | handle NS | libc NS
> +      =======+===========+============+========+===========+=========
> +      dlmopen-rtld-shared1:
> +      -------+-----------+------------+--------+-----------+---------
> +       -     | 0         | -          | +0     | 0         | 0
> +       0     | 0         | -          | 0      | 0         | 0
> +       0     | 0         | SHARED     | 0      | 0         | 0
> +       0     | +         | -          | 0,+1   | 1         | 0
> +       0,1   | 0         | -          | 0,1    | 0         | 0
> +       0,1   | 0         | SHARED     | 0,1    | 0         | 0

Maybe add that each line represents a different test here?


> +      =======+===========+============+========+===========+=========
> +      dlmopen-rtld-shared2:
> +      -------+-----------+------------+--------+-----------+---------
> +       -     | 0         | SHARED     | +0     | 0         | 0
> +       0     | +         | SHARED     | 0,+1p  | 1p        | 0
> +       0,1p  | 0         | -          | 0,1p   | 0         | 0
> +       0,1p  | 0         | SHARED     | 0,1p   | 0         | 0
> +       0,1p  | 1         | -          | 0,1p   | 1p        | 0
> +       0,1p  | 1         | SHARED     | 0,1p   | 1p        | 0
> +      =======+===========+============+========+===========+=========
> +      dlmopen-rtld-shared3
> +      -------+-----------+------------+--------+-----------+---------
> +       -     | +         | -          | +1     | 1         | 0
> +       1     | 0         | -          | +0,1   | 0         | 0
> +       0,1   | 1         | -          | 0,1    | 1         | 0
> +       0,1   | 1         | SHARED     | 0,1    | ERR       | -
> +      =======+===========+============+========+===========+=========
> +      dlmopen-rtld-shared4
> +      -------+-----------+------------+--------+-----------+---------
> +       -     | +         | SHARED     | +0,+1p | 1p        | 0
> +      =======+===========+============+========+===========+=========
> +      dlmopen-rtld-shared5
> +      -------+-----------+------------+--------+-----------+---------
> +       1     | 0         | SHARED     | +0,1   | 0         | 0
> +      =======+===========+============+========+===========+=========
> +      dlmopen-rtld-shared6
> +      -------+-----------+------------+--------+-----------+---------
> +       1     | 1         | -          | 1      | 0         | 0
> +       1     | 1         | SHARED     | 1      | ERR       | -
> +
> +      Target is a DF_GNU_1_UNIQUE DSO:
> +      Before | Target NS | RTLD Flags | After  | handle NS | libc NS
> +      =======+===========+============+========+===========+=========
> +      dlmopen-rtld-unique1:
> +      -------+-----------+------------+--------+-----------+---------
> +       -     | 0         | -          | +0     | 0         | 0
> +       0     | 0         | -          | 0      | 0         | 0
> +       0     | 0         | SHARED     | 0      | 0         | 0
> +       0     | +         | -          | 0,+1p  | 1p        | 0
> +       0,1p  | 0         | -          | 0,1p   | 0         | 0
> +       0,1p  | 0         | SHARED     | 0,1p   | 0         | 0
> +       0,1p  | 1         | -          | 0,1p   | 1p        | 0
> +       0,1p  | 1         | SHARED     | 0,1p   | 1p        | 0
> +      =======+===========+============+========+===========+=========
> +      dlmopen-rtld-unique2:
> +      -------+-----------+------------+--------+-----------+---------
> +       -     | 0         | SHARED     | +0     | 0         | 0
> +       0     | +         | SHARED     | 0,+1p  | 1p        | 0
> +      =======+===========+============+========+===========+=========
> +      dlmopen-rtld-unique3:
> +      -------+-----------+------------+--------+-----------+---------
> +       -     | +         | -          | +0,+1p | 1p        | 0
> +      =======+===========+============+========+===========+=========
> +      dlmopen-rtld-unique4:
> +      -------+-----------+------------+--------+-----------+---------
> +       -     | +         | SHARED     | +0,+1p | 1p        | 0
> +      =======+===========+============+========+===========+=========
> +      dlmopen-rtld-unique5:
> +      -------+-----------+------------+--------+-----------+---------
> +       -     | +         | ISOLATE    | +1     | 1         | 1
> +       1     | 0         | -          | +0,1   | 0         | 0
> +       0,1   | 0         | -          | 0,1    | 0         | 0
> +       0,1   | 0         | SHARED     | 0,1    | 0         | 0
> +       0,1   | 1         | -          | 0,1    | ERR       | -
> +      =======+===========+============+========+===========+=========
> +      dlmopen-rtld-unique6:
> +      -------+-----------+------------+--------+-----------+---------
> +       -     | +1        | ISOLATE    | +1     | 1         | 1
> +       1     | 1         | -          | 1      | ERR       | -
> +       1     | 1         | SHARED     | 1      | ERR       | -
> +       1     | 0         | SHARED     | +0,1   | 0         | 0
> +       0,1   | 1         | SHARED     | 0,1    | ERR       | -
> +*/
> +
> +#include "tst-dlmopen-common.h"
> +#include <dl-dtprocnum.h>
> +#include <link.h>
> +
> +#define DSO_NORMAL "$ORIGIN/tst-dlmopen-sharedmod-norm.so"
> +#define DSO_UNIQUE "$ORIGIN/tst-dlmopen-sharedmod-uniq.so"
> +#define DSO_TESTFN "rtld_shared_testfunc"
> +#define DSO_NAMESTUB "tst-dlmopen-sharedmod-"
> +#define MAX_NS 16
> +
> +#define END_TESTS { .name = NULL },
> +
> +#define ERROR(test, fmt, ...) \
> +  ({ if (last_test != test)                                        \
> +       printf ("FAILED: %s (%s):\n", test->name, test->desc);      \
> +     printf ("%s @ %d - " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \
> +     last_test = test; })

Use support/check.h here.

> +
> +static void *last_test;
> +
> +typedef enum
> +  {
> +   NONE  = 0,
> +   DSO   = 1,
> +   PROXY = 2,
> +   NEW   = 4,
> +  } dso_type;
> +
> +typedef struct
> +{
> +  const char *name;
> +  const char *desc;
> +  int is_prep_stage;
> +  const char *dso_name;
> +  int failure;
> +
> +  struct
> +  {
> +    const char *dso_path;
> +    Lmid_t ns;
> +    int flags;
> +  } args;
> +
> +  dso_type preloaded[MAX_NS];
> +  dso_type loaded[MAX_NS];
> +  dso_type handle_type;
> +  Lmid_t handle_ns;
> +  Lmid_t free_ns;
> +} dlmopen_test_spec;
> +
> +struct r_scope_elem
> +{
> +  struct tst_lm **r_list;
> +  unsigned int r_nlist;
> +};
> +
> +/* This is a copy of the first part of the internal definition of
> +   struct link_map from <include/link.h>.  We use it to check some
> +   expected internal state that's not readily accessible via public APIs.
> + */

I think these tests should be marked as 'tests-internal' so you can include
the internal definition instead of replicate the defition below.

> +struct tst_lm
> +  {
> +    /* These first few members are part of the protocol with the debugger.
> +       This is the same format used in SVR4.  */
> +
> +    ElfW(Addr) l_addr;		/* Difference between the address in the ELF
> +                                   file and the addresses in memory.  */
> +    char *l_name;		/* Absolute file name object was found in.  */
> +    ElfW(Dyn) *l_ld;		/* Dynamic section of the shared object.  */
> +    struct tst_lm *l_next, *l_prev; /* Chain of loaded objects.  */
> +
> +    /* All following members are internal to the dynamic linker.
> +       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 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 tst_lm *l_real;
> +
> +    /* Number of the namespace this link map belongs to.  */
> +    Lmid_t l_ns;
> +
> +    struct libname_list *l_libname;
> +    /* Indexed pointers to dynamic section.
> +       [0,DT_NUM) are indexed by the processor-independent tags.
> +       [DT_NUM,DT_NUM+DT_THISPROCNUM) are indexed by the tag minus DT_LOPROC.
> +       [DT_NUM+DT_THISPROCNUM,DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM) are
> +       indexed by DT_VERSIONTAGIDX(tagvalue).
> +       [DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM,
> +        DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM) are indexed by
> +       DT_EXTRATAGIDX(tagvalue).
> +       [DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM,
> +        DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM) are
> +       indexed by DT_VALTAGIDX(tagvalue) and
> +       [DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM,
> +        DT_NUM+DT_THISPROCNUM+DT_VERSIONTAGNUM+DT_EXTRANUM+DT_VALNUM+DT_ADDRNUM)
> +       are indexed by DT_ADDRTAGIDX(tagvalue), see <elf.h>.  */
> +
> +    ElfW(Dyn) *l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM
> +                      + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
> +    const ElfW(Phdr) *l_phdr;	/* Pointer to program header table in core.  */
> +    ElfW(Addr) l_entry;		/* Entry point location.  */
> +    ElfW(Half) l_phnum;		/* Number of program header entries.  */
> +    ElfW(Half) l_ldnum;		/* Number of dynamic segment entries.  */
> +
> +    /* Array of DT_NEEDED dependencies and their dependencies, in
> +       dependency order for symbol lookup (with and without
> +       duplicates).  There is no entry before the dependencies have
> +       been loaded.  */
> +    struct r_scope_elem l_searchlist;
> +
> +    /* We need a special searchlist to process objects marked with
> +       DT_SYMBOLIC.  */
> +    struct r_scope_elem l_symbolic_searchlist;
> +
> +    /* Dependent object that first caused this object to be loaded.  */
> +    struct link_map *l_loader;
> +
> +    /* Array with version names.  */
> +    struct r_found_version *l_versions;
> +    unsigned int l_nversions;
> +
> +    /* Symbol hash table.  */
> +    Elf_Symndx l_nbuckets;
> +    Elf32_Word l_gnu_bitmask_idxbits;
> +    Elf32_Word l_gnu_shift;
> +    const ElfW(Addr) *l_gnu_bitmask;
> +    union
> +    {
> +      const Elf32_Word *l_gnu_buckets;
> +      const Elf_Symndx *l_chain;
> +    };
> +    union
> +    {
> +      const Elf32_Word *l_gnu_chain_zero;
> +      const Elf_Symndx *l_buckets;
> +    };
> +
> +    unsigned int l_direct_opencount; /* Reference count for dlopen/dlclose.  */
> +    enum			/* Where this object came from.  */
> +      {
> +        lt_executable,		/* The main executable program.  */
> +        lt_library,		/* Library needed by main executable.  */
> +        lt_loaded		/* Extra run-time loaded shared object.  */
> +      } l_type:2;
> +    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.  */
> +    unsigned int l_soname_added:1; /* Nonzero if the SONAME is for sure in
> +                                      the l_libname list.  */
> +    unsigned int l_faked:1;	/* Nonzero if this is a faked descriptor
> +                                   without associated file.  */
> +    unsigned int l_need_tls_init:1; /* Nonzero if GL(dl_init_static_tls)
> +                                       should be called on this link map
> +                                       when relocation finishes.  */
> +    unsigned int l_auditing:1;	/* Nonzero if the DSO is used in auditing.  */
> +    unsigned int l_audit_any_plt:1; /* Nonzero if at least one audit module
> +                                       is interested in the PLT interception.*/
> +    unsigned int l_removed:1;	/* Nozero if the object cannot be used anymore
> +                                   since it is removed.  */
> +    unsigned int l_contiguous:1; /* Nonzero if inter-segment holes are
> +                                    mprotected or if no holes are present at
> +                                    all.  */
> +    unsigned int l_symbolic_in_local_scope:1; /* Nonzero if l_local_scope
> +                                                 during LD_TRACE_PRELINKING=1
> +                                                 contains any DT_SYMBOLIC
> +                                                 libraries.  */
> +    unsigned int l_free_initfini:1; /* Nonzero if l_initfini can be
> +                                       freed, ie. not allocated with
> +                                       the dummy malloc in ld.so.  */
> +  };
> +
> +typedef struct { void *handle; Lmid_t ns; } test_handle;
> +static test_handle cached_handles[32];
> +
> +static void
> +cache_test_handle (void *handle, Lmid_t ns)
> +{
> +  int i;
> +
> +  for (i = 0; i < sizeof(cached_handles)/sizeof(test_handle); i++)

Use array_length.h here.

> +    if (cached_handles[i].handle == NULL)
> +      {
> +        cached_handles[i].handle = handle;
> +        cached_handles[i].ns = ns;
> +        break;
> +      }
> +}
> +
> +__attribute__((unused))
> +static struct tst_lm *
> +link_map_of_dl_handle (void *handle)
> +{
> +  struct tst_lm *lm = NULL;
> +
> +  if (dlinfo (handle, RTLD_DI_LINKMAP, &lm) == 0)
> +    return lm;
> +
> +  printf ("dlinfo (LINKMAP) for %s in %s failed: %s\n",
> +          LIBC_SO, __func__, dlerror ());
> +
> +  return NULL;
> +}
> +

Ok.

> +__attribute__((unused))
> +static Lmid_t
> +ns_of_dl_handle (void *handle)
> +{
> +  Lmid_t ns = 0;
> +
> +  if (dlinfo (handle, RTLD_DI_LMID, &ns) == 0)
> +    return ns;
> +
> +  printf ("dlinfo (LMID) for %s in %s failed: %s\n",
> +          LIBC_SO, __func__, dlerror ());
> +
> +  return -1;
> +}
> +

Ok.

> +__attribute__((unused))
> +static Lmid_t real_ns_of_dl_handle (void *handle)
> +{
> +  Lmid_t ns = 0;
> +  struct tst_lm *lm = link_map_of_dl_handle (handle);
> +
> +  if (lm == NULL)
> +    return -1;
> +
> +  // printf ("DEBUG: handle %p; LM %p; proxy: %d / %p\n",
> +  // handle, lm, lm->l_proxy, lm->l_real);

Comments should be in C style (/* */).  Same for other occurances.

> +
> +  if (lm->l_proxy)
> +    {
> +      // printf ("DEBUG: proxy %p vs real %p\n", lm, lm->l_real);
> +      ns = ns_of_dl_handle ((void *) lm->l_real);
> +    }

Usually in such cases there is no need to add brackets.

> +  else
> +    ns = ns_of_dl_handle (handle);
> +
> +  return ns;
> +}
> +
> +__attribute__((unused))
> +static const char *str_soname (const char *name)
> +{
> +  char *slash = NULL;
> +
> +  if (name == NULL)
> +    return NULL;
> +
> +  if ((slash = strrchr (name, '/')))
> +    return ++slash;
> +  else
> +    return name;
> +}
> +

Ok.

> +__attribute__((unused))
> +static const char *lm_name (struct tst_lm *lm)
> +{
> +  if (lm)
> +    return lm->l_name;
> +
> +  return NULL;
> +}
> +

Ok.

> +
> +static int dlm_dso_is_loaded (void *handle)
> +{
> +  if (handle != RTLD_DEFAULT)
> +    {
> +#ifdef DEBUG_DSO_LOADCHECK
> +      Dl_info sinfo = {};
> +#endif

Is is a left over of development debugging? Otherwise you can add this
as verbose output (check support/test-driver.h and test_verbose internal
usage).

However I think this are useful and it would be better to add as
default for the tests.

> +
> +      if (((struct tst_lm *) handle)->l_type != lt_loaded)
> +        return 0;
> +
> +#ifdef DEBUG_DSO_LOADCHECK
> +      printf ("checking %p %s for %s\n",
> +              handle, ((struct tst_lm *)handle)->l_name, DSO_TESTFN);
> +#endif
> +
> +      void *symbol = dlsym (handle, DSO_TESTFN);
> +
> +#ifdef DEBUG_DSO_LOADCHECK
> +      dladdr (symbol, &sinfo);
> +      printf ("  -> %s (in %s (%p))\n",
> +              sinfo.dli_fname,
> +              sinfo.dli_sname,
> +              sinfo.dli_saddr);
> +#endif
> +
> +      return symbol ? 1 : 0;
> +    }
> +
> +  for (int i = 0; i < sizeof(cached_handles)/sizeof(test_handle); i++)

Use array_length.h here.

> +    {
> +      if (cached_handles[i].handle == NULL)
> +        break;
> +
> +      if (((struct tst_lm *) cached_handles[i].handle)->l_type != lt_loaded)
> +        continue;
> +
> +#ifdef DEBUG_DSO_LOADCHECK
> +      printf ("checking %p %s for %s\n",
> +              cached_handles[i].handle,
> +              ((struct tst_lm *)cached_handles[i].handle)->l_name,
> +              DSO_TESTFN);
> +#endif
> +
> +      if (dlsym (cached_handles[i].handle, DSO_TESTFN) != NULL)
> +        return 1;
> +    }
> +
> +  return 0;
> +}

Ok.

> +
> +static int call_testfunc (dlmopen_test_spec *test, void *handle)

I think the code guidelines state function name should be after a new line.

> +{
> +  Dl_info dli = {};
> +  struct tst_lm *lm = NULL;
> +  dlmopen_testfunc func = NULL;
> +  dlmopen_testresult *result = NULL;
> +
> +  if (handle != RTLD_DEFAULT)
> +    func = dlsym (handle, DSO_TESTFN);
> +
> +  if (func == NULL)
> +    {
> +      ERROR (test, "test function %s not found\n", DSO_TESTFN);

Use support/check.h functions here and in other failures cases.

> +      return 0;
> +    }
> +
> +  result = (func)();
> +
> +  if (result == NULL)
> +    {
> +      ERROR (test, "test function %s returned NULL\n", DSO_TESTFN);
> +      return 0;
> +    }
> +
> +  dladdr1 (result->free, &dli, (void **)&lm, RTLD_DL_LINKMAP);
> +
> +  if (lm == NULL)
> +    {
> +      ERROR (test, "free() implementation from test module is invalid\n");
> +      return 0;
> +    }
> +
> +  if (lm->l_ns != test->free_ns)
> +    {
> +      ERROR (test,
> +             "free() function from test module was from ns %d, expected %d\n",
> +             (int)lm->l_ns, (int)test->free_ns);
> +      return 0;
> +    }
> +
> +  printf ("%s: %s: %s in ns %d using free() from ns %d: OK\n",
> +          test->name, test->args.dso_path, DSO_TESTFN,
> +          (int)test->handle_ns, (int)lm->l_ns);
> +
> +  return 1;
> +}

Ok.

> +
> +static void *link_map_snapshot_array (void *handle, void *func, Lmid_t ns, size_t *len)
> +{
> +  struct tst_lm *lm = NULL;
> +  struct tst_lm *start = NULL;
> +
> +  if (len)

No implict checks.

> +    *len = 0;
> +
> +  if (handle != NULL)
> +    {
> +      dlinfo (handle, RTLD_DI_LINKMAP, &lm);
> +    }
> +  else if (func != NULL)
> +    {
> +      Dl_info dli = {};
> +
> +      dladdr1 (func, &dli, (void **)&lm, RTLD_DL_LINKMAP);
> +    }
> +  else if (ns >= LM_ID_BASE)
> +    {
> +      for (int i = 0; i < sizeof(cached_handles)/sizeof(test_handle); i++)

Use array_length.h here.

> +        {
> +          if (cached_handles[i].handle == NULL)
> +            break;
> +
> +          if (cached_handles[i].ns != ns)
> +            continue;
> +
> +          dlinfo (cached_handles[i].handle, RTLD_DI_LINKMAP, &lm);
> +          break;
> +        }
> +    }
> +
> +  if (lm == NULL)
> +    return NULL;
> +
> +  start = lm;
> +
> +  while (start->l_prev)

No implicit checks.

> +    start = start->l_prev;
> +
> +  size_t lm_size = 0;
> +
> +  for (lm = start; lm; lm = lm->l_next)

No implicits checks.

> +    lm_size++;
> +
> +  struct tst_lm **lm_list = calloc (lm_size + 1, sizeof (struct tst_lm *));

Use xcalloc here.

> +
> +  if (len)
> +    *len = lm_size;
> +
> +  int i = 0;
> +
> +  for (lm = start; lm; lm = lm->l_next)
> +    lm_list[i++] = lm;
> +  lm_list[i] = NULL;
> +
> +  return lm_list;
> +}
> +
> +__attribute__((unused))
> +static int search_link_map_array (struct tst_lm **lma, size_t len, void *handle)
> +{
> +  if (lma == NULL)
> +    return 0;
> +
> +  if (len == 0)
> +    return 0;
> +  
> +  struct tst_lm *target = link_map_of_dl_handle (handle);
> +
> +  for (int i = 0; i < len; i++)
> +    {
> +      //printf ("searching for %p in <%p>[%d] == %p\n",
> +      //        handle, lma, i, lma[i]);
> +      if (handle == (struct tst_lm *)(lma[i]))
> +        return 1;
> +
> +      if (target->l_proxy)
> +        if (target->l_real == (struct tst_lm *)(lma[i]))
> +          return 1;
> +    }
> +
> +  return 0;
> +}
> +
> +#ifdef DEBUG_DSO_SEARCH
> +#define TRACE2(fmt, ...) \
> +  printf ("  find-test-dso (%s @ %d): " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
> +#else
> +#define TRACE2(fmt, ...) 
> +#endif
> +
> +static struct tst_lm *
> +find_test_dso_in_link_map_array (struct tst_lm **lma, size_t len)
> +{
> +  if (lma == NULL)
> +    return NULL;
> +
> +  if (len == 0)
> +    return NULL;
> +
> +  for (int i = 0; i < len; i++)
> +    {
> +      if (!lma[i] || !lma[i]->l_name)

No implicit checks with pointers.

> +        continue;
> +
> +      TRACE2 ("%p [%d/%d] %s", lma, i, (int)len - 1,
> +              lma[i] ? (lma[i]->l_name ?: "???.so") : "NULL" );
> +
> +      if (lma[i] && lma[i]->l_name)
> +        if (strstr (lma[i]->l_name, DSO_NAMESTUB))
> +          if (dlsym (lma[i], DSO_TESTFN) != NULL)
> +            return (struct tst_lm *)lma[i];
> +    }
> +  
> +  return NULL;
> +}
> +
> +__attribute__((unused))
> +static void *link_map_list (void *handle, void *func, int *len, Lmid_t *ns)
> +{
> +  struct tst_lm *lm = NULL;
> +  struct tst_lm *start = NULL;
> +
> +  if (len)
> +    *len = 0;
> +
> +  if (handle != NULL)
> +    {
> +      dlinfo (handle, RTLD_DI_LINKMAP, &lm);
> +    }
> +  else if (func != NULL)
> +    {
> +      Dl_info dli = {};
> +
> +      dladdr1 (func, &dli, (void **)&lm, RTLD_DL_LINKMAP);
> +    }
> +
> +  if (lm == NULL)
> +    return NULL;
> +
> +  if (ns)
> +    *ns = lm->l_ns;
> +
> +  // rewind to start of link map list:
> +  start = lm;
> +
> +  while (start->l_prev)
> +    start = start->l_prev;
> +
> +  size_t lm_size = 0;
> +
> +  for (lm = start; lm; lm = lm->l_next)
> +    lm_size++;
> +
> +  if (len)
> +    *len = lm_size;
> +
> +  return start;
> +}
> +
> +#ifdef DEBUG_DLMOPEN_TEST_WRAPPER
> +#define TRACE(fmt, ...) \
> +  printf ("%s (%s @ %d): " fmt "\n", test->name, __FILE__, __LINE__, ##__VA_ARGS__)
> +#else
> +#define TRACE(fmt, ...)
> +#endif
> +
> +static int process_test_spec (dlmopen_test_spec *test)

Maybe return bool here.

> +{
> +  void *handle = NULL;
> +  size_t lm_before_len[MAX_NS] = { 0 };
> +  size_t lm_after_len[MAX_NS] = { 0 };
> +  struct tst_lm **lm_before[MAX_NS] = { NULL };
> +  struct tst_lm **lm_after[MAX_NS] = { NULL };
> +  struct tst_lm *preloads[MAX_NS] = { NULL };
> +  int want_preload = 0;
> +  int test_status = 0;
> +
> +  memset (&lm_after[0], 0, sizeof (lm_after));
> +  memset (&lm_before[0], 0, sizeof (lm_before));
> +  memset (&preloads[0], 0, sizeof (preloads));

You already initialized all arrays.

> +
> +  TRACE("LD_AUDIT = %s", getenv("LD_AUDIT") ?: "-");
> +  TRACE("BEFORE SNAPSHOTS: %p", &lm_before[0]);
> +  TRACE("AFTER  SNAPSHOTS: %p", &lm_after[0]);
> +  TRACE("preloads        : %p", preloads);
> +  TRACE("setup done");
> +  
> +  if (test->args.dso_path && *test->args.dso_path && !test->dso_name)
> +    test->dso_name = str_soname (test->args.dso_path);
> +
> +  TRACE("DSO short name: %s", test->dso_name);
> +  
> +  // get the existing link map contents before the test runs:
> +  lm_before[0] = link_map_snapshot_array (NULL, process_test_spec,
> +                                          LM_ID_BASE, &lm_before_len[0]);
> +  for (int i = 1; i < MAX_NS; i++)
> +    lm_before[i] = link_map_snapshot_array (NULL, NULL, i, &lm_before_len[i]);
> +
> +  TRACE("link map snapshots cached");
> +  
> +  for (int i = 0; i < MAX_NS; i++)
> +    {
> +      if (test->preloaded[i] & PROXY)
> +        {
> +          struct tst_lm **lm = lm_before[i];
> +          want_preload++;
> +
> +          if (lm != NULL)
> +            for (int j = 0; !preloads[i] && (j < lm_before_len[i]); j++)
> +              if (dlm_dso_is_loaded (lm[j]) && lm[j]->l_proxy)
> +                preloads[i] = lm[j];
> +
> +          if (!preloads[i])

No implicit checks.

> +            {
> +              ERROR (test,
> +                     "needed proxy for %s preloaded in NS %d, not found\n",
> +                     test->dso_name, i);
> +              goto cleanup;
> +            }
> +        }
> +      else if (test->preloaded[i] & DSO)
> +        {
> +          struct tst_lm **lm = lm_before[i];
> +          int lm_max = lm_before_len[i];
> +          want_preload++;
> +
> +          if (lm != NULL)
> +            for (int j = 0; !preloads[i] && (j < lm_max); j++)
> +              {
> +                if (dlm_dso_is_loaded (lm[j]) && !lm[j]->l_proxy)
> +                  preloads[i] = lm[j];
> +              }
> +          if (!preloads[i])
> +            {
> +              ERROR (test,
> +                     "needed %s preloaded in NS %d, not found\n",
> +                     test->dso_name, i);
> +              goto cleanup;
> +            }
> +        }
> +    }
> +  TRACE("preload checks (A)");

Ok.

> +  
> +  if (dlm_dso_is_loaded (RTLD_DEFAULT))
> +    {
> +      // test DSO module must _not_ be preloaded, and is:
> +      if (!want_preload)
> +        {
> +          ERROR (test, "DSO %s unexpectedly loaded before test\n", test->dso_name);
> +          goto cleanup;
> +        }
> +    }
> +  else
> +    {
> +      // DSO is not loaded, and must be:
> +      // In theory we can never see this error as it
> +      // should be caught by the preceding preload loop:
> +      if (want_preload)
> +        {
> +          ERROR (test, "DSO %s must be preloaded (and is not)\n", test->args.dso_path);
> +          goto cleanup;
> +        }
> +    }
> +  TRACE("preload checks (B) %s", test->name);

Ok.

> +
> +  if (!(test->args.flags & (RTLD_NOW|RTLD_LAZY)))
> +    test->args.flags |= RTLD_NOW;
> +
> +  handle = dlmopen (test->args.ns, test->args.dso_path, test->args.flags);
> +  TRACE("dlmopen returned %p", handle);
> +
> +  if (handle == NULL)
> +    {
> +      const char *status = "failed";
> +
> +      if (test->failure)
> +        {
> +          status = "failed (EXPECTED)";
> +          test_status = 1;
> +
> +          printf ("%s: dlmopen(%s, %d, 0x%0x) failed: OK\n",
> +                  test->name, test->args.dso_path,
> +                  (int)test->args.ns, (int)test->args.flags);
> +          printf ("Returned: %p\n\n", handle);
> +
> +          goto cleanup;
> +        }
> +
> +      ERROR (test, "");
> +
> +      if (test->is_prep_stage)
> +        printf ("(during setup of preconditions): ");
> +      else
> +        printf (": ");
> +
> +      if (test->args.ns == LM_ID_BASE)
> +        printf ("dlmopen (LM_ID_BASE, \"%s\", 0x%x) %s: %s\n",
> +                test->args.dso_path, test->args.flags, status, dlerror ());
> +      else
> +        printf ("dlmopen (%d, \"%s\", 0x%x) %s: %s\n",
> +                (int)test->args.ns, test->args.dso_path, test->args.flags, status, dlerror ());
> +
> +      goto cleanup;
> +    }
> +  else if (test->failure)
> +    {
> +      ERROR (test, "dlmopen() call should have failed, but did not\n");
> +      goto cleanup;
> +    }
> +
> +  TRACE("return status checked");

Ok.

> +
> +  if (!dlm_dso_is_loaded (handle))
> +    {
> +      ERROR (test, "DSO %s (%p) missing function (%s)\n",
> +             test->args.dso_path, handle, DSO_TESTFN);
> +      goto cleanup;
> +    }
> +
> +  TRACE ("loaded DSO sanity checked");
> +
> +  Lmid_t hns = ns_of_dl_handle (handle);
> +  Lmid_t real_hns = real_ns_of_dl_handle (handle);
> +  Lmid_t proxy_ns = 0;
> +
> +  call_testfunc (test, handle);
> +  TRACE (DSO_TESTFN "called");
> +
> +  cache_test_handle (handle, hns);
> +  TRACE ("handle %p cached (ns %d)", handle, (int)hns);
> +
> +  // if the real ns was different to the apparent one
> +  // then we have a proxy and we need to shuffle the values,
> +  // else leave the proxy ns as 0 as an expect.proxy_ns of 0
> +  // means we weren't expecting a proxy:> +  if (real_hns != hns)
> +    {
> +      proxy_ns = hns;
> +      hns = real_hns;
> +    }
> +
> +  if (proxy_ns)
> +    printf ("Returned: proxy ns:%d (real ns: %d)\n\n", (int)proxy_ns, (int)hns);
> +  else
> +    printf ("Returned: dso ns:%d\n\n", (int)hns);
> +
> +  Lmid_t expected;
> +  if (test->handle_type & PROXY)
> +    expected = proxy_ns;
> +  else
> +    expected = hns;
> +
> +  TRACE("check expected ns %d", (int)expected);
> +

Ok.

> +  if (test->args.ns == LM_ID_NEWLM)
> +    {
> +      if (expected <= LM_ID_BASE)
> +        {
> +          ERROR (test, "DSO should have been in NS > %d, was in %d\n",
> +                 LM_ID_BASE, (int)expected);
> +          goto cleanup;
> +        }
> +
> +      // for any cases where we can't predict
> +      // the namespace in advance:
> +      if (test->handle_ns == LM_ID_NEWLM)
> +        test->handle_ns = expected;
> +    }
> +  else
> +    {
> +      if (test->args.ns != expected)
> +        {
> +          ERROR (test, "DSO should have been in NS %d, was in %d\n",
> +                 (int)test->args.ns, (int)expected);
> +          goto cleanup;
> +        }
> +    }
> +
> +  TRACE("ns %d Ok", (int)expected);

Ok.

> +
> +  if (test->handle_type & PROXY) // expecting a proxy
> +    {
> +      if (proxy_ns != 0) // got a proxy
> +        {
> +          if (test->handle_ns != proxy_ns) // but not in the right place
> +            {
> +              ERROR (test, "DSO proxy should have been in ns %d, was in %d\n",
> +                     (int)test->handle_ns, (int)proxy_ns);
> +              goto cleanup;
> +            }
> +        }
> +      else // didn't get a proxy
> +        {
> +          ERROR (test,
> +                 "DSO should have been a proxy in ns %d,"
> +                 " was a non-proxy in ns %d\n",
> +                 (int)test->handle_ns, (int)hns);
> +          goto cleanup;
> +        }
> +    }
> +  else // not expecting a proxy
> +    {
> +      if (proxy_ns > 0)
> +        {
> +          ERROR (test,
> +                 "DSO should NOT have been a proxy,"
> +                 " was a proxy in ns %d (real ns %d)\n",
> +                 (int)proxy_ns, (int)hns);
> +          goto cleanup;
> +        }
> +
> +      if (test->handle_ns != hns)
> +        {
> +          ERROR (test,
> +                 "DSO should have been in ns %d,"
> +                 " was in ns %d\n",
> +                 (int)test->handle_ns, (int)hns);
> +          goto cleanup;
> +        }
> +    }
> +  TRACE ("proxy status Ok");

Ok.

> +
> +  // get the new link map contents after the test has run:
> +  lm_after[0] = link_map_snapshot_array (NULL, process_test_spec,
> +                                         LM_ID_BASE, &lm_after_len[0]);
> +  for (int i = 1; i < MAX_NS; i++)
> +    lm_after[i] = link_map_snapshot_array (NULL, NULL, i, &lm_after_len[i]);
> +
> +  for (int i = 0; i < MAX_NS; i++)
> +    {
> +      TRACE("checking status of NS %d", i);
> +      void *old_handle =
> +        find_test_dso_in_link_map_array (lm_before[i], lm_before_len[i]);
> +      TRACE ("old handle is %p", old_handle);
> +
> +      void *new_handle =
> +        find_test_dso_in_link_map_array (lm_after[i], lm_after_len[i]);
> +      TRACE ("new handle is %p", new_handle);
> +
> +      if (test->loaded[i] == NONE)
> +        {
> +          TRACE ("ns %d requirement is NONE", i);
> +          if (old_handle != NULL)
> +            {
> +              ERROR (test,
> +                     "Unexpected preload DSO %s in ns %d\n",
> +                     lm_name (old_handle), i);
> +              goto cleanup;
> +            }
> +          if (new_handle != NULL)
> +            {
> +              ERROR (test, "Unexpected new DSO %s in ns %d\n",
> +                     lm_name (new_handle), i);
> +              goto cleanup;
> +            }
> +          continue;
> +        }
> +
> +      if (test->loaded[i] & NEW)
> +        {
> +          TRACE("ns %d requirement is NEW", i);
> +          if (old_handle != NULL)
> +            {
> +              ERROR (test,
> +                     "DSO in ns %d should have been a new load,"
> +                     " found to have been preloaded\n", i);
> +              goto cleanup;
> +            }
> +          if (new_handle == NULL)
> +            {
> +              ERROR (test, "Expected DSO in ns %d, not found\n", i);
> +              goto cleanup;
> +            }
> +        }
> +      else
> +        {
> +          TRACE("ns %d requirement is OLD", i);
> +          if (new_handle == NULL)
> +            {
> +              ERROR (test, "Expected new DSO in ns %d, not found\n", i);
> +              goto cleanup;
> +            }
> +
> +          if (old_handle != new_handle)
> +            {
> +              ERROR (test, "DSO in ns %d changed. This should be impossible, "
> +                     "sanity check the test code in %s\n", i, __FILE__);
> +              goto cleanup;
> +            }
> +        }
> +
> +      if (test->loaded[i] & PROXY)
> +        {
> +          TRACE ("rechecking DSO status in ns %d", i);
> +          if (!((struct tst_lm *)new_handle)->l_proxy)
> +            {
> +              ERROR (test, "DSO in ns %d should be a proxy but is not\n", i);
> +              goto cleanup;
> +            }
> +        }
> +      else
> +        {
> +          TRACE ("rechecking proxy status in ns %d", i);
> +          if (((struct tst_lm *)new_handle)->l_proxy)
> +            {
> +              ERROR (test, "DSO in ns %d should NOT be a proxy but is\n", i);
> +              goto cleanup;
> +            }
> +        }
> +    }
> +
> +  test_status = 1;

Ok.

> +
> + cleanup:
> +  for (int i = 0; i < MAX_NS; i++)
> +     free (lm_after[i]);
> +  for (int i = 0; i < MAX_NS; i++)
> +    free (lm_before[i]);
> +
> +  return test_status;
> +}
> +
> +

Ok.

> diff --git a/elf/tst-dlmopen-modules.h b/elf/tst-dlmopen-modules.h
> new file mode 100644
> index 0000000000..4bbf431ec3
> --- /dev/null
> +++ b/elf/tst-dlmopen-modules.h
> @@ -0,0 +1,20 @@
> +#pragma once
> +/* Module-specific infrastructure for tst-dlmopen-rtld-*
> +   Copyright © 2020 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.

s/2020/s2021

> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include "tst-dlmopen-common.h"
> diff --git a/elf/tst-dlmopen-rtld-audit-shared1.c b/elf/tst-dlmopen-rtld-audit-shared1.c
> new file mode 100644
> index 0000000000..1e9f604327
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-audit-shared1.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 2
> +#include "tst-dlmopen-rtld-shared1.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-audit-shared2.c b/elf/tst-dlmopen-rtld-audit-shared2.c
> new file mode 100644
> index 0000000000..53064dd345
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-audit-shared2.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 2
> +#include "tst-dlmopen-rtld-shared2.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-audit-shared3.c b/elf/tst-dlmopen-rtld-audit-shared3.c
> new file mode 100644
> index 0000000000..de90bc1258
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-audit-shared3.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 2
> +#include "tst-dlmopen-rtld-shared3.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-audit-shared4.c b/elf/tst-dlmopen-rtld-audit-shared4.c
> new file mode 100644
> index 0000000000..c600b2f4dc
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-audit-shared4.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 2
> +#include "tst-dlmopen-rtld-shared4.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-audit-shared5.c b/elf/tst-dlmopen-rtld-audit-shared5.c
> new file mode 100644
> index 0000000000..cd223d041b
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-audit-shared5.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 2
> +#include "tst-dlmopen-rtld-shared5.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-audit-shared6.c b/elf/tst-dlmopen-rtld-audit-shared6.c
> new file mode 100644
> index 0000000000..f84303b1b4
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-audit-shared6.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 2
> +#include "tst-dlmopen-rtld-shared6.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-audit-unique1.c b/elf/tst-dlmopen-rtld-audit-unique1.c
> new file mode 100644
> index 0000000000..f60b9c05d4
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-audit-unique1.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 2
> +#include "tst-dlmopen-rtld-unique1.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-audit-unique2.c b/elf/tst-dlmopen-rtld-audit-unique2.c
> new file mode 100644
> index 0000000000..199b1d3606
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-audit-unique2.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 2
> +#include "tst-dlmopen-rtld-unique2.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-audit-unique3.c b/elf/tst-dlmopen-rtld-audit-unique3.c
> new file mode 100644
> index 0000000000..f3ebe58828
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-audit-unique3.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 2
> +#include "tst-dlmopen-rtld-unique3.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-audit-unique4.c b/elf/tst-dlmopen-rtld-audit-unique4.c
> new file mode 100644
> index 0000000000..ef555672d2
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-audit-unique4.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 2
> +#include "tst-dlmopen-rtld-unique4.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-audit-unique5.c b/elf/tst-dlmopen-rtld-audit-unique5.c
> new file mode 100644
> index 0000000000..b7faa5d02c
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-audit-unique5.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 2
> +#include "tst-dlmopen-rtld-unique5.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-audit-unique6.c b/elf/tst-dlmopen-rtld-audit-unique6.c
> new file mode 100644
> index 0000000000..d431e3a787
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-audit-unique6.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 2
> +#include "tst-dlmopen-rtld-unique6.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-shared1.c b/elf/tst-dlmopen-rtld-shared1.c
> new file mode 100644
> index 0000000000..812d21e692
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-shared1.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 1
> +#include "tst-dlmopen-rtld-shared1.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-shared1.h b/elf/tst-dlmopen-rtld-shared1.h
> new file mode 100644
> index 0000000000..bd733cb3c4
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-shared1.h
> @@ -0,0 +1,65 @@
> +static dlmopen_test_spec dltest[] =
> +  {
> +   {
> +    .name = "dlmopen:0:none--ns0",
> +    .desc = "dlmopen as dlopen",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_BASE,
> +    .loaded = { [0] = DSO|NEW },
> +    .handle_type = DSO,
> +    .handle_ns = LM_ID_BASE,
> +   },
> +   {
> +    .name = "dlmopen:0:ns0--ns0",
> +    .desc = "dlmopen a preloaded DSO in the base NS",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_BASE,
> +    .preloaded = { [0] = DSO },
> +    .loaded = { [0] = DSO },
> +    .handle_type = DSO,
> +    .handle_ns = LM_ID_BASE,
> +   },
> +   {
> +    .name = "dlmopen-shared:0:ns0--ns0",
> +    .desc = "dlmopen a preloaded DSO in the base NS with RTLD_SHARED",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_BASE,
> +    .args.flags = RTLD_SHARED,
> +    .preloaded = { [0] = DSO },
> +    .loaded = { [0] = DSO },
> +    .handle_type = DSO,
> +    .handle_ns = LM_ID_BASE,
> +   },
> +   {
> +    .name = "dlmopen:0:ns0--nsX",
> +    .desc = "dlmopen a preloaded DSO in the base NS into a new NS",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_NEWLM,
> +    .preloaded = { [0] = DSO },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO|NEW },
> +    .handle_type = DSO,
> +    .handle_ns = EXPECTED_NS,
> +   },
> +   {
> +    .name = "dlmopen:0:ns0-nsX--ns0-nsX",
> +    .desc = "dlmopen a preloaded DSO in the base & secondary NS into the base NS",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_BASE,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +    .handle_type = DSO,
> +    .handle_ns = LM_ID_BASE,
> +   },
> +   {
> +    .name = "dlmopen-shared:0:ns0-nsX--ns0-nsX",
> +    .desc = "dlmopen a preloaded DSO in the base & secondary NS into the base NS",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_BASE,
> +    .args.flags = RTLD_SHARED,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +    .handle_type = DSO,
> +    .handle_ns = LM_ID_BASE,
> +   },
> +   END_TESTS
> +  };

Ok.

> diff --git a/elf/tst-dlmopen-rtld-shared2.c b/elf/tst-dlmopen-rtld-shared2.c
> new file mode 100644
> index 0000000000..f830832a0a
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-shared2.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 1
> +#include "tst-dlmopen-rtld-shared2.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-shared2.h b/elf/tst-dlmopen-rtld-shared2.h
> new file mode 100644
> index 0000000000..9775619b9a
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-shared2.h
> @@ -0,0 +1,67 @@
> +static dlmopen_test_spec dltest[] =
> +  {
> +   {
> +    .name = "dlmopen-shared:0:none--ns0",
> +    .desc = "dlmopen as dlopen with RTLD_SHARED",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_BASE,
> +    .args.flags  = RTLD_SHARED,
> +    .loaded = { [0] = DSO|NEW },
> +    .handle_ns = LM_ID_BASE,
> +    .handle_type = DSO,
> +   },
> +   {
> +    .name = "dlmopen-shared:X:ns0--ns0-nsXp",
> +    .desc = "dlmopen into a new namespace with the target already in the base NS",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_NEWLM,
> +    .args.flags = RTLD_SHARED,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = PROXY,
> +    .preloaded = { [0] = DSO },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY|NEW }
> +   },
> +   {
> +    .name = "dlmopen:0:ns0-nsXp--ns0-nsXp",
> +    .desc = "dlmopen into base NS while proxy already in nsX",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_BASE,
> +    .handle_ns = 0,
> +    .handle_type = DSO,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +   },
> +   {
> +    .name = "dlmopen-shared:0:ns0-nsXp--ns0-nsXp",
> +    .desc = "dlmopen with RTLD_SHARED into base NS while proxy already in nsX",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_BASE,
> +    .args.flags = RTLD_SHARED,
> +    .handle_ns = 0,
> +    .handle_type = DSO,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +   },
> +   {
> +    .name = "dlmopen:X:ns0-nsXp--ns0-nsXp",
> +    .desc = "dlmopen into NS X while proxy already in nsX",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = EXPECTED_NS,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = PROXY,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +   },
> +   {
> +    .name = "dlmopen-shared:X:ns0-nsXp--ns0-nsXp",
> +    .desc = "dlmopen with RTLD_SHARED into NS X while proxy already in nsX",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = EXPECTED_NS,
> +    .args.flags = RTLD_SHARED,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = PROXY,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +   },
> +   END_TESTS
> +  };

Ok.

> diff --git a/elf/tst-dlmopen-rtld-shared3.c b/elf/tst-dlmopen-rtld-shared3.c
> new file mode 100644
> index 0000000000..a63753eb84
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-shared3.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 1
> +#include "tst-dlmopen-rtld-shared3.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>

Ok.

> diff --git a/elf/tst-dlmopen-rtld-shared3.h b/elf/tst-dlmopen-rtld-shared3.h
> new file mode 100644
> index 0000000000..23fce58bae
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-shared3.h
> @@ -0,0 +1,44 @@
> +static dlmopen_test_spec dltest[] =
> +  {
> +   {
> +    .name = "dlmopen:X:none--nsX",
> +    .desc = "dlmopen into nsX, no copies preloaded",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_NEWLM,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = DSO,
> +    .preloaded = { },
> +    .loaded = { [EXPECTED_NS] = DSO|NEW },
> +   },
> +   {
> +    .name = "dlmopen:0:nsX--ns0-nsX",
> +    .desc = "dlmopen into ns 0, copy already loaded in ns X",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_BASE,
> +    .handle_ns = 0,
> +    .handle_type = DSO,
> +    .preloaded = { [EXPECTED_NS] = DSO },
> +    .loaded = { [0] = DSO|NEW, [EXPECTED_NS] = DSO },
> +   },
> +   {
> +    .name = "dlmopen:X:ns0-nsX--nsX",
> +    .desc = "dlmopen into ns X, copies already in ns 0 and ns X",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = EXPECTED_NS,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = DSO,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +   },
> +   {
> +    .name = "dlmopen-shared:X:ns0-nsX--nsX",
> +    .desc = "dlmopen RTLD_SHARED into nsX with a DSO already in NS0 and NSX",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = EXPECTED_NS,
> +    .args.flags = RTLD_SHARED,
> +    .failure = 1,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +   },
> +   END_TESTS
> +  };


Ok.


> diff --git a/elf/tst-dlmopen-rtld-shared4.c b/elf/tst-dlmopen-rtld-shared4.c
> new file mode 100644
> index 0000000000..7c3d92e37b
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-shared4.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 1
> +#include "tst-dlmopen-rtld-shared4.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>
> diff --git a/elf/tst-dlmopen-rtld-shared4.h b/elf/tst-dlmopen-rtld-shared4.h
> new file mode 100644
> index 0000000000..9ad29b9a6d
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-shared4.h
> @@ -0,0 +1,15 @@
> +static dlmopen_test_spec dltest[] =
> +  {
> +   {
> +    .name = "dlmopen-shared:X:none--ns0-nsX",
> +    .desc = "dlmopen a new proxy in nsX with no preexisting dso in ns0",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_NEWLM,
> +    .args.flags = RTLD_SHARED,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = PROXY,
> +    .preloaded = { },
> +    .loaded = { [0] = DSO|NEW, [EXPECTED_NS] = PROXY|NEW },
> +   },
> +   END_TESTS
> +  };


Ok.


> diff --git a/elf/tst-dlmopen-rtld-shared5.c b/elf/tst-dlmopen-rtld-shared5.c
> new file mode 100644
> index 0000000000..f59d14e7b6
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-shared5.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 1
> +#include "tst-dlmopen-rtld-shared5.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>
> diff --git a/elf/tst-dlmopen-rtld-shared5.h b/elf/tst-dlmopen-rtld-shared5.h
> new file mode 100644
> index 0000000000..220129a5cf
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-shared5.h
> @@ -0,0 +1,26 @@
> +static dlmopen_test_spec dltest[] =
> +  {
> +   {
> +    .name = "dlmopen-preload:X:none--nsX",
> +    .desc = "preload a DSO into ns1 to prepare for other tests",
> +    .is_prep_stage = 1,
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_NEWLM,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = DSO,
> +    .preloaded = { },
> +    .loaded = { [EXPECTED_NS] = DSO|NEW },
> +   },
> +   {
> +    .name = "dlmopen-shared:0:nsX--nsX-ns0",
> +    .desc = "dlmopen RTLD_SHARED into ns0 when preloaded into nsX",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_BASE,
> +    .args.flags = RTLD_SHARED,
> +    .handle_ns = 0,
> +    .handle_type = DSO,
> +    .preloaded = { [EXPECTED_NS] = DSO },
> +    .loaded = { [0] = DSO|NEW, [EXPECTED_NS] = DSO },
> +   },
> +   END_TESTS
> +  };
> diff --git a/elf/tst-dlmopen-rtld-shared6.c b/elf/tst-dlmopen-rtld-shared6.c
> new file mode 100644
> index 0000000000..469fb3566d
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-shared6.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 1
> +#include "tst-dlmopen-rtld-shared6.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>
> diff --git a/elf/tst-dlmopen-rtld-shared6.h b/elf/tst-dlmopen-rtld-shared6.h
> new file mode 100644
> index 0000000000..116e53ea51
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-shared6.h
> @@ -0,0 +1,37 @@
> +static dlmopen_test_spec dltest[] =
> +  {
> +   {
> +    .name = "dlmopen-preload:X:none--nsX",
> +    .desc = "preload a DSO into nsX to prepare for other tests",
> +    .is_prep_stage = 1,
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = LM_ID_NEWLM,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = DSO,
> +    .preloaded = { },
> +    .loaded = { [EXPECTED_NS] = DSO|NEW },
> +   },
> +   {
> +    .name = "dlmopen:X:nsX--nsX",
> +    .desc = "dlmopen a dso in nsX while already loaded there",
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = EXPECTED_NS,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = DSO,
> +    .preloaded = { [EXPECTED_NS] = DSO },
> +    .loaded = { [EXPECTED_NS] = DSO },
> +   },
> +   {
> +    .name = "dlmopen-shared:X:nsX--nsX",
> +    .desc = "dlmopen RTLD_SHARED a dso in nsX while already loaded there",
> +    .failure = 1,
> +    .args.dso_path = DSO_NORMAL,
> +    .args.ns = EXPECTED_NS,
> +    .args.flags = RTLD_SHARED,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = DSO,
> +    .preloaded = { [EXPECTED_NS] = DSO },
> +    .loaded = { [EXPECTED_NS] = DSO },
> +   },
> +   END_TESTS
> +  };
> diff --git a/elf/tst-dlmopen-rtld-unique1.c b/elf/tst-dlmopen-rtld-unique1.c
> new file mode 100644
> index 0000000000..867345582f
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-unique1.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 1
> +#include "tst-dlmopen-rtld-unique1.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>
> diff --git a/elf/tst-dlmopen-rtld-unique1.h b/elf/tst-dlmopen-rtld-unique1.h
> new file mode 100644
> index 0000000000..f7d32959c2
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-unique1.h
> @@ -0,0 +1,87 @@
> +static dlmopen_test_spec dltest[] =
> +  {
> +   {
> +    .name = "dlmopen-unique:0:none--ns0",
> +    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into ns0",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_BASE,
> +    .handle_ns = 0,
> +    .handle_type = DSO,
> +    .preloaded = { },
> +    .loaded = { [0] = DSO|NEW },
> +   },
> +   {
> +    .name = "dlmopen-unique:0:ns0--ns0",
> +    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into ns0 while already present",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_BASE,
> +    .handle_ns = 0,
> +    .handle_type = DSO,
> +    .preloaded = { [0] = DSO },
> +    .loaded = { [0] = DSO },
> +   },
> +   {
> +    .name = "dlmopen-unique-shared:0:ns0--ns0",
> +    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso into ns0 while already present",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_BASE,
> +    .args.flags = RTLD_SHARED,
> +    .handle_ns = 0,
> +    .handle_type = DSO,
> +    .preloaded = { [0] = DSO },
> +    .loaded = { [0] = DSO },
> +   },
> +   {
> +    .name = "dlmopen-unique:X:ns0--nsX",
> +    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into nsX while present in ns0",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_NEWLM,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = PROXY,
> +    .preloaded = { [0] = DSO },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY|NEW },
> +   },
> +   {
> +    .name = "dlmopen-unique:0:ns0-nsXp--ns0--nsXp",
> +    .desc = "dlmopen a DF_GNU_1_UNIQUE dso already in ns0 proxied in nsX",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_BASE,
> +    .handle_ns = 0,
> +    .handle_type = DSO,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +   },
> +   {
> +    .name = "dlmopen-shared-unique:0:ns0-nsXp--ns0-nsXp",
> +    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso into ns0 already in ns0 and proxied in nsX",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_BASE,
> +    .args.flags = RTLD_SHARED,
> +    .handle_ns = 0,
> +    .handle_type = DSO,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +   },
> +   {
> +    .name = "dlmopen-unique:0:ns0-nsXp--ns0-nsXp",
> +    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into ns0 already in ns0 and proxied in nsX",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = EXPECTED_NS,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = PROXY,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +   },
> +   {
> +    .name = "dlmopen-unique:0:ns0-nsXp--ns0-nsXp",
> +    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso into ns0 already in ns0 and proxied in nsX",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = EXPECTED_NS,
> +    .args.flags = RTLD_SHARED,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = PROXY,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY },
> +   },
> +   END_TESTS
> +  };
> diff --git a/elf/tst-dlmopen-rtld-unique2.c b/elf/tst-dlmopen-rtld-unique2.c
> new file mode 100644
> index 0000000000..dabb87b43f
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-unique2.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 1
> +#include "tst-dlmopen-rtld-unique2.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>
> diff --git a/elf/tst-dlmopen-rtld-unique2.h b/elf/tst-dlmopen-rtld-unique2.h
> new file mode 100644
> index 0000000000..911e0180ab
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-unique2.h
> @@ -0,0 +1,26 @@
> +static dlmopen_test_spec dltest[] =
> +  {
> +   {
> +    .name = "dlmopen-shared-unique:0:none--ns0",
> +    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso in the base ns",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_BASE,
> +    .args.flags = RTLD_SHARED,
> +    .handle_ns = 0,
> +    .handle_type = DSO,
> +    .preloaded = { },
> +    .loaded = { [0] = DSO|NEW },
> +   },
> +   {
> +    .name = "dlmopen-shared-unique:1:ns0--ns0-ns1p",
> +    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso into ns1 while present in ns0",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_NEWLM,
> +    .args.flags = RTLD_SHARED,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = PROXY,
> +    .preloaded = { [0] = DSO },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = PROXY|NEW },
> +   },
> +   END_TESTS
> +  };
> diff --git a/elf/tst-dlmopen-rtld-unique3.c b/elf/tst-dlmopen-rtld-unique3.c
> new file mode 100644
> index 0000000000..db8a567a3f
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-unique3.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 1
> +#include "tst-dlmopen-rtld-unique3.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>
> diff --git a/elf/tst-dlmopen-rtld-unique3.h b/elf/tst-dlmopen-rtld-unique3.h
> new file mode 100644
> index 0000000000..b400bad07f
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-unique3.h
> @@ -0,0 +1,14 @@
> +static dlmopen_test_spec dltest[] =
> +  {
> +   {
> +    .name = "dlmopen-unique:X:none--ns0-ns1p",
> +    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into nsX",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_NEWLM,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = PROXY,
> +    .preloaded = { },
> +    .loaded = { [0] = DSO|NEW, [EXPECTED_NS] = PROXY|NEW },
> +   },
> +   END_TESTS
> +  };
> diff --git a/elf/tst-dlmopen-rtld-unique4.c b/elf/tst-dlmopen-rtld-unique4.c
> new file mode 100644
> index 0000000000..58b8e017b4
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-unique4.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 1
> +#include "tst-dlmopen-rtld-unique4.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>
> diff --git a/elf/tst-dlmopen-rtld-unique4.h b/elf/tst-dlmopen-rtld-unique4.h
> new file mode 100644
> index 0000000000..36d5915172
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-unique4.h
> @@ -0,0 +1,15 @@
> +static dlmopen_test_spec dltest[] =
> +  {
> +   {
> +    .name = "dlmopen-shared-unique:X:none--ns0-nsXp",
> +    .desc = "dlmopen a DF_GNU_1_UNIQUE dso",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_NEWLM,
> +    .args.flags = RTLD_SHARED,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = PROXY,
> +    .preloaded = { },
> +    .loaded = { [0] = DSO|NEW, [EXPECTED_NS] = PROXY|NEW },
> +   },
> +   END_TESTS
> +  };
> diff --git a/elf/tst-dlmopen-rtld-unique5.c b/elf/tst-dlmopen-rtld-unique5.c
> new file mode 100644
> index 0000000000..b2e8329461
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-unique5.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 1
> +#include "tst-dlmopen-rtld-unique5.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>
> diff --git a/elf/tst-dlmopen-rtld-unique5.h b/elf/tst-dlmopen-rtld-unique5.h
> new file mode 100644
> index 0000000000..29882ea782
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-unique5.h
> @@ -0,0 +1,59 @@
> +static dlmopen_test_spec dltest[] =
> +  {
> +   {
> +    .name = "dlmopen-isolate-unique:X:none--nsX",
> +    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into NSX with RTLD_ISOLATE",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_NEWLM,
> +    .args.flags = RTLD_ISOLATE,
> +    .handle_ns = EXPECTED_NS,
> +    .free_ns = EXPECTED_NS,
> +    .handle_type = DSO,
> +    .preloaded = { },
> +    .loaded = { [EXPECTED_NS] = DSO|NEW },
> +   },
> +   {
> +    .name = "dlmopen-unique:0:nsX--ns0-nsX",
> +    .desc = "dlmopen a DF_GNU_1_UNIQUE dso already present in NS X",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_BASE,
> +    .handle_ns = 0,
> +    .handle_type = DSO,
> +    .preloaded = { [EXPECTED_NS] = DSO },
> +    .loaded = { [0] = DSO|NEW, [EXPECTED_NS] = DSO },
> +   },
> +   {
> +    .name = "dlmopen-unique:0:ns0-nsX--ns0-nsX",
> +    .desc = "dlmopen a DF_GNU_1_UNIQUE dso already in the base NS and NS X",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_BASE,
> +    .handle_ns = 0,
> +    .handle_type = DSO,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +   },
> +   {
> +    .name = "dlmopen-shared-unique:0:ns0-nsX--ns0-nsX",
> +    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso already in the base NS and NS X",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_BASE,
> +    .args.flags = RTLD_SHARED,
> +    .handle_ns = 0,
> +    .handle_type = DSO,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +   },
> +   {
> +    .name = "dlmopen-shared-unique:X:ns0-nsX--ns0-nsX",
> +    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso already in the base NS and NS X into NS X",
> +    .failure = 1,
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = EXPECTED_NS,
> +    .args.flags = RTLD_SHARED,
> +    .handle_ns = EXPECTED_NS,
> +    .handle_type = DSO,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +    .loaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +   },
> +   END_TESTS
> +  };
> diff --git a/elf/tst-dlmopen-rtld-unique6.c b/elf/tst-dlmopen-rtld-unique6.c
> new file mode 100644
> index 0000000000..fecaf559a3
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-unique6.c
> @@ -0,0 +1,11 @@
> +#include <dlfcn.h>
> +#include "tst-dlmopen-main.h"
> +
> +#define EXPECTED_NS 1
> +#include "tst-dlmopen-rtld-unique6.h"
> +
> +#include "tst-dlmopen-std-do-test.h"
> +
> +DEFINE_DLMOPEN_TEST(dltest)
> +
> +#include <support/test-driver.c>
> diff --git a/elf/tst-dlmopen-rtld-unique6.h b/elf/tst-dlmopen-rtld-unique6.h
> new file mode 100644
> index 0000000000..3c25127fa1
> --- /dev/null
> +++ b/elf/tst-dlmopen-rtld-unique6.h
> @@ -0,0 +1,52 @@
> +static dlmopen_test_spec dltest[] =
> +  {
> +   {
> +    .name = "dlmopen-isolate-unique:1:none--ns1--prep",
> +    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into NS1 with RTLD_ISOLATE",
> +    .is_prep_stage = 1,
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_NEWLM,
> +    .args.flags = RTLD_ISOLATE,
> +    .handle_ns = EXPECTED_NS,
> +    .free_ns = EXPECTED_NS,
> +    .handle_type = DSO,
> +    .preloaded = { },
> +    .loaded = { [EXPECTED_NS] = DSO|NEW },
> +   },
> +   {
> +    .name = "dlmopen-unique:1:nsX--nsX--FAIL",
> +    .desc = "dlmopen a DF_GNU_1_UNIQUE dso into NSX when already there",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = EXPECTED_NS,
> +    .failure = 1,
> +    .preloaded = { [EXPECTED_NS] = DSO },
> +   },
> +   {
> +    .name = "dlmopen-shared-unique:X:nsX--nsX--FAIL",
> +    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso into NSX when already there",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = EXPECTED_NS,
> +    .args.flags = RTLD_SHARED,
> +    .failure = 1,
> +    .preloaded = { [EXPECTED_NS] = DSO },
> +   },
> +   {
> +    .name = "dlmopen-shared-unique:0:nsX--ns0-nsX",
> +    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso already present in NS X",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = LM_ID_BASE,
> +    .handle_ns = 0,
> +    .handle_type = DSO,
> +    .preloaded = { [EXPECTED_NS] = DSO },
> +    .loaded = { [0] = DSO|NEW, [EXPECTED_NS] = DSO },
> +   },
> +   {
> +    .name = "dlmopen-shared-unique:X:ns0-nsX--ns0-nsX--FAIL",
> +    .desc = "dlmopen RTLD_SHARED a DF_GNU_1_UNIQUE dso already in the base NS and NS 1",
> +    .args.dso_path = DSO_UNIQUE,
> +    .args.ns = EXPECTED_NS,
> +    .failure = 1,
> +    .preloaded = { [0] = DSO, [EXPECTED_NS] = DSO },
> +   },
> +   END_TESTS
> +  };
> diff --git a/elf/tst-dlmopen-sharedmod-norm.c b/elf/tst-dlmopen-sharedmod-norm.c
> new file mode 100644
> index 0000000000..fd049903f4
> --- /dev/null
> +++ b/elf/tst-dlmopen-sharedmod-norm.c
> @@ -0,0 +1,11 @@
> +#include "tst-dlmopen-modules.h"
> +
> +dlmopen_testresult *rtld_shared_testfunc (void)
> +{
> +  static dlmopen_testresult result;
> +
> +  result.name = "norm";
> +  result.free = free;
> +
> +  return &result;
> +}


Ok.

> diff --git a/elf/tst-dlmopen-sharedmod-uniq.c b/elf/tst-dlmopen-sharedmod-uniq.c
> new file mode 100644
> index 0000000000..5c9701da41
> --- /dev/null
> +++ b/elf/tst-dlmopen-sharedmod-uniq.c
> @@ -0,0 +1,11 @@
> +#include "tst-dlmopen-modules.h"
> +
> +dlmopen_testresult *rtld_shared_testfunc (void)
> +{
> +  static dlmopen_testresult result;
> +
> +  result.name = "noop";
> +  result.free = free;
> +
> +  return &result;
> +}


Ok.


> diff --git a/elf/tst-dlmopen-std-do-test.h b/elf/tst-dlmopen-std-do-test.h
> new file mode 100644
> index 0000000000..595f6f764d
> --- /dev/null
> +++ b/elf/tst-dlmopen-std-do-test.h
> @@ -0,0 +1,11 @@
> +#pragma once
> +
> +#define DEFINE_DLMOPEN_TEST(x) \
> +  static int                          \
> +  do_test (void)                      \
> +  {                                   \
> +    for (int i = 0; x[i].name; i++)   \
> +      if (!process_test_spec (&x[i])) \
> +        return 1;                     \
> +    return 0;                         \
> +  }
> 

You can the array_length macro to avoid add a END_TESTS and maybe define
it a .c file instead of macro:

---
$ cat elf/tst-dlmopen-std-do-test.c
#include <array-lenght.h>

static int
do_test (void)
{
  for (int i = 0; i < array_length (tests); i++)
    if (!process_test_spec (&x[i]))
      return 1;
  return 0;
}
#include <support/test-driver.c>
---

So you can just add a '#include "tst-dlmopen-std-do-test.c"' instead.

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

* Re: [RFC][PATCH v8 19/20] Add dlmopen / RTLD_SHARED tests
  2021-02-09 17:18 ` [RFC][PATCH v8 19/20] Add dlmopen / RTLD_SHARED tests Vivek Das Mohapatra via Libc-alpha
  2021-02-26 19:50   ` Adhemerval Zanella via Libc-alpha
@ 2021-02-26 20:26   ` Andreas Schwab
  1 sibling, 0 replies; 78+ messages in thread
From: Andreas Schwab @ 2021-02-26 20:26 UTC (permalink / raw
  To: Vivek Das Mohapatra via Libc-alpha

On Feb 09 2021, Vivek Das Mohapatra via Libc-alpha wrote:

> diff --git a/elf/tst-dlmopen-auditmod.c b/elf/tst-dlmopen-auditmod.c
> new file mode 100644
> index 0000000000..04457249d0
> --- /dev/null
> +++ b/elf/tst-dlmopen-auditmod.c
> @@ -0,0 +1,23 @@
> +/* Audit module for tst-dlmopen-rtld-audit-*
> +   Copyright © 2020 Free Software Foundation, Inc.

Please don't use non-ascii in sources.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."

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

* Re: [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen
  2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
                   ` (21 preceding siblings ...)
  2021-02-12 18:52 ` Adhemerval Zanella via Libc-alpha
@ 2021-03-04 18:27 ` Adhemerval Zanella via Libc-alpha
  22 siblings, 0 replies; 78+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2021-03-04 18:27 UTC (permalink / raw
  To: Vivek Das Mohapatra, GNU C Library



On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote:
> This is a revision of a previous patchset that I posted here
> regarding https://sourceware.org/bugzilla/show_bug.cgi?id=22745 
> 
> Introduction:
> 
> =======================================================================
>   As discussed in the URL above dlmopen requires a mechanism for
>   [optionally] sharing some objects between more than one namespace.
> 
>   The following patchset provides 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 implements the following:
> 
>  - dlmopen will implicitly apply RTLD_SHARED to the libc/libpthread group
>    (requires a patched binutils/ld so that the libc family DSOs can
>    be flagged as requiring this behaviour)
> 
>    - binutils patchset accepted upstream;
>    - https://sourceware.org/git/?p=binutils-gdb.git
>    - commit 8a87b2791181eb7fc1533ffaeb95df8d87d41493
> 
>  - LD_AUDIT paths will NOT apply this implict sharing rule:
>    audit libraries will continue to be completely isolated.
> 
>  - The mechanism for tagging DSOs as implicitly shared has been changed
>    from a DT_FLAGS_1 flag to a DT_VALRNGHI/LO range dynamic section tag.
>    (Based on feedback on the binutils side of this patch series).
> 
>   - DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE
> 
>  - A flag RTLD_ISOLATE which is used inernally to suppress RTLD_SHARED
>    behaviour when audit libraries are being loaded, and is also made available
>    to users who really want a completely separate copy of glibc in their new
>    namespace.
> 
>  - Tests for the new dlmopen behaviour
> 
>  - Adds the unique dso flag to htl/libpthread.so as well as nptl
> 
> 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 (20):
>   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
>   elf/dl-open.c: Don't try libc linit in namespaces with no libc mapping
>   elf/dl-open.c: when creating a proxy check the libc_map in NS 0
>   Define a new dynamic section tag - DT_GNU_FLAGS_1
>   Abstract the loaded-DSO search code into a private helper function
>   Compare loaded DSOs by file ID and check for DF_GNU_1_UNIQUE
>   Use the new DSO finder helper function since we have it
>   Use the DSO search helper to check for preloaded DT_GNU_UNIQUE DSOs
>   When loading DSOs into alternate namespaces check for DT_GNU_UNIQUE
>   Suppress audit calls when a (new) namespace is empty
>   Suppress inter-namespace DSO sharing for audit libraries
>   dlsym, dlvsym should be able to look up symbols via DSO proxies
>   Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs
>   Add dlmopen / RTLD_SHARED tests
>   Restore separate libc loading for the TLS/namespace storage test

Now that I have reviewed all the patches, I think the set should be reorganized
to each patch being logically consistent and not requiring to have all patches
applied in a bulk to get RTLD_SHARED/RTLD_ISOLATE support fully implemented.

So besides fixing all the implicit and style issues (missing space, attribute 
out of 'if', etc.) I think the patch should be logically implemented as:

  1. Move the 09/20 to first in set (it adds the new binutils definitions
     and set the l_gnu_flags_1).  The new definitions are used only 
     internally and the new flag is only set but not used on the patch.

  2. Move the 10/20 to second in set (it adds a function used in subsequent
     patch). It add a new function which is used on code refactoring.

  3. Split the 12/20 a patch to do *just* the refactor that uses the
     _dl_find_dso and move the RTLD_ISOLATE to the patch that actually 
     enables RTLD_SHARED.

  4. Add a patch to add the DT_GNU_FLAGS_1 dynamic tag on the required
     library (it should be safer since there is no logic yet that consumes it).

  5. Combine all the remaining patch that enable RTLD_SHARED and RT_ISOLATE
     on a single patch. It would be large patch, but it is more logically
     consistent and easier to revert or backport.

  6. Add the tests.

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

end of thread, other threads:[~2021-03-04 18:27 UTC | newest]

Thread overview: 78+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-02-09 17:18 [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Vivek Das Mohapatra via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 01/20] Declare and describe the dlmopen RTLD_SHARED flag Vivek Das Mohapatra via Libc-alpha
2021-02-15 13:08   ` Adhemerval Zanella via Libc-alpha
2021-02-15 13:29     ` Andreas Schwab
2021-02-15 13:31       ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 02/20] include/link.h: Update the link_map struct to allow proxies Vivek Das Mohapatra via Libc-alpha
2021-02-15 13:11   ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 03/20] elf/dl-object.c: Implement a helper function to proxy link_map entries Vivek Das Mohapatra via Libc-alpha
2021-02-15 13:30   ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 04/20] elf/dl-load.c, elf-dl-open.c: Implement RTLD_SHARED dlmopen proxying Vivek Das Mohapatra via Libc-alpha
2021-02-15 14:53   ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 05/20] elf/dl-fini.c: Handle proxy link_map entries in the shutdown path Vivek Das Mohapatra via Libc-alpha
2021-02-15 17:08   ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 06/20] elf/dl-init.c: Skip proxied link map entries in the dl init path Vivek Das Mohapatra via Libc-alpha
2021-02-15 17:52   ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 07/20] elf/dl-open.c: Don't try libc linit in namespaces with no libc mapping Vivek Das Mohapatra via Libc-alpha
2021-02-15 17:54   ` Adhemerval Zanella via Libc-alpha
2021-02-17 15:39     ` Vivek Das Mohapatra via Libc-alpha
2021-02-17 16:17       ` Adhemerval Zanella via Libc-alpha
2021-02-17 18:32         ` Vivek Das Mohapatra via Libc-alpha
2021-02-17 20:52           ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 08/20] elf/dl-open.c: when creating a proxy check the libc_map in NS 0 Vivek Das Mohapatra via Libc-alpha
2021-02-15 17:55   ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 09/20] Define a new dynamic section tag - DT_GNU_FLAGS_1 Vivek Das Mohapatra via Libc-alpha
2021-02-15 18:42   ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 10/20] Abstract the loaded-DSO search code into a private helper function Vivek Das Mohapatra via Libc-alpha
2021-02-15 19:25   ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 11/20] Compare loaded DSOs by file ID and check for DF_GNU_1_UNIQUE Vivek Das Mohapatra via Libc-alpha
2021-02-18 20:45   ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 12/20] Use the new DSO finder helper function since we have it Vivek Das Mohapatra via Libc-alpha
2021-02-19 14:39   ` Adhemerval Zanella via Libc-alpha
2021-02-19 19:50     ` Adhemerval Zanella via Libc-alpha
2021-02-22 18:44     ` Vivek Das Mohapatra via Libc-alpha
2021-02-22 18:51       ` Adhemerval Zanella via Libc-alpha
2021-02-22 23:50         ` Vivek Das Mohapatra via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 13/20] Use the DSO search helper to check for preloaded DT_GNU_UNIQUE DSOs Vivek Das Mohapatra via Libc-alpha
2021-02-19 17:26   ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 14/20] When loading DSOs into alternate namespaces check for DT_GNU_UNIQUE Vivek Das Mohapatra via Libc-alpha
2021-02-19 18:11   ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 15/20] Suppress audit calls when a (new) namespace is empty Vivek Das Mohapatra via Libc-alpha
2021-02-19 19:45   ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 16/20] Suppress inter-namespace DSO sharing for audit libraries Vivek Das Mohapatra via Libc-alpha
2021-02-19 20:39   ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 17/20] dlsym, dlvsym should be able to look up symbols via DSO proxies Vivek Das Mohapatra via Libc-alpha
2021-02-22 18:51   ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 18/20] Add DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE dynamic section+flag to glibc DSOs Vivek Das Mohapatra via Libc-alpha
2021-02-22 20:39   ` Adhemerval Zanella via Libc-alpha
2021-02-22 21:19     ` Florian Weimer via Libc-alpha
2021-02-22 21:53       ` Adhemerval Zanella via Libc-alpha
2021-02-23  3:26         ` Alan Modra via Libc-alpha
2021-02-23 11:57           ` Adhemerval Zanella via Libc-alpha
2021-02-23 10:00         ` Florian Weimer via Libc-alpha
2021-02-23 11:58           ` Adhemerval Zanella via Libc-alpha
2021-02-23 12:12             ` Florian Weimer via Libc-alpha
2021-02-23  0:17     ` Vivek Das Mohapatra via Libc-alpha
2021-02-23 12:02       ` Adhemerval Zanella via Libc-alpha
2021-02-23 13:24         ` Adhemerval Zanella via Libc-alpha
2021-02-23 18:46           ` Vivek Das Mohapatra via Libc-alpha
2021-02-23 18:48             ` Adhemerval Zanella via Libc-alpha
2021-02-23 19:01               ` Florian Weimer via Libc-alpha
2021-02-23 19:06                 ` Adhemerval Zanella via Libc-alpha
2021-02-09 17:18 ` [RFC][PATCH v8 19/20] Add dlmopen / RTLD_SHARED tests Vivek Das Mohapatra via Libc-alpha
2021-02-26 19:50   ` Adhemerval Zanella via Libc-alpha
2021-02-26 20:26   ` Andreas Schwab
2021-02-09 17:18 ` [RFC][PATCH v8 20/20] Restore separate libc loading for the TLS/namespace storage test Vivek Das Mohapatra via Libc-alpha
2021-02-09 19:01 ` [RFC][PATCH v8 00/20] Implementation of RTLD_SHARED for dlmopen Joseph Myers
2021-02-10 12:25   ` Vivek Das Mohapatra via Libc-alpha
2021-02-10 18:32     ` Joseph Myers
2021-02-12 18:52 ` Adhemerval Zanella via Libc-alpha
2021-02-12 18:56   ` Florian Weimer via Libc-alpha
2021-02-12 19:01     ` Adhemerval Zanella via Libc-alpha
2021-02-12 19:29       ` Florian Weimer via Libc-alpha
2021-02-18 14:41   ` Vivek Das Mohapatra via Libc-alpha
2021-02-18 15:02     ` Florian Weimer via Libc-alpha
2021-02-18 15:05       ` Vivek Das Mohapatra via Libc-alpha
2021-02-19  8:57         ` Florian Weimer via Libc-alpha
2021-02-19 15:08           ` Vivek Das Mohapatra via Libc-alpha
2021-03-04 18:27 ` Adhemerval Zanella 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).