diff mbox series

[RFC,v4,13/15] Suppress inter-namespace DSO sharing for audit libraries

Message ID aad32603b239ad2407a6778c311b94b4272e9bd9.1585588166.git.vivek@collabora.com
State New
Headers show
Series Proof-of-Concept implementation of RTLD_SHARED for dlmopen | expand

Commit Message

Vivek Das Mohapatra March 30, 2020, 5:43 p.m. UTC
Audit libraries should not participate in DSO sharing: In
particular libraries tagged with DF_1_UNIQUE should not be
shared between the audit namespace and any others - they
should get their own copy.

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

Patch

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