[RFC][PATCH v6 16/20] Suppress inter-namespace DSO sharing for audit libraries

Vivek Das Mohapatra vivek@collabora.com
Tue Dec 15 18:44:56 GMT 2020


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 9170059323..2f1f7c04fa 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 9bd4884a88..22c0e92a1d 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 84f27dd1c6..62ed2a084f 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 526360237f..f127df2c53 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -657,7 +657,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 fc33fd184e..a21755a868 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



More information about the Libc-alpha mailing list