From 4058a11e0b1e6ce9e16ce63dd7c970379c0587a2 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Wed, 8 Nov 2017 13:56:58 +0000
Subject: [PATCH] Include a pointer to the namespace in the capsule structure

Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 capsule/capsule-dlmopen.c  |  6 +--
 capsule/capsule-init.c     | 80 +++++++++++++++++++-------------------
 capsule/capsule-private.h  | 10 ++++-
 capsule/capsule-wrappers.c | 10 ++---
 capsule/capsule.h          |  1 -
 5 files changed, 57 insertions(+), 50 deletions(-)

diff --git a/capsule/capsule-dlmopen.c b/capsule/capsule-dlmopen.c
index d6fd6208c..3ddf18b9c 100644
--- a/capsule/capsule-dlmopen.c
+++ b/capsule/capsule-dlmopen.c
@@ -276,9 +276,7 @@ capsule_load (const capsule cap,
                 capsule other = ptr_list_nth_ptr( _capsule_list, n );
 
                 // this subcapsule is for a different prefix. skip it:
-                //DEBUG( DEBUG_CAPSULE, "checking prefix match: %p vs %p",
-                //       cap->prefix, other->meta->active_prefix );
-                if( strcmp( cap->prefix, other->prefix ) )
+                if( cap->ns != other->ns )
                     continue;
 
                 // we found a pre-allocated Lmid_t. Use it:
@@ -294,7 +292,7 @@ capsule_load (const capsule cap,
 
     if( !ld_libs_init( &ldlibs,
                        (const char **) cap->meta->combined_exclude,
-                       cap->meta->active_prefix, debug_flags, errcode, error ) )
+                       cap->ns->prefix, debug_flags, errcode, error ) )
         return NULL;
 
     // ==================================================================
diff --git a/capsule/capsule-init.c b/capsule/capsule-init.c
index 568af1c20..bd243fc55 100644
--- a/capsule/capsule-init.c
+++ b/capsule/capsule-init.c
@@ -22,13 +22,11 @@
               "struct _capsule %p"                     "\n"  \
               "{"                                      "\n"  \
               "  void        *dl_handle;          %p"  "\n"  \
-              "  char        *prefix;             %s"  "\n"  \
               "  capsule_metadata *meta;          %p"  "\n"  \
               "  {"                                    "\n"  \
               "    Lmid_t namespace;              %ld" "\n"  \
               "    const char  *soname;           %s"  "\n"  \
               "    const char  *default_prefix;   %s"  "\n"  \
-              "    char        *active_prefix;    %s"  "\n"  \
               "    const char **exclude;          %p"  "\n"  \
               "    const char **export;           %p"  "\n"  \
               "    const char **nowrap;           %p"  "\n"  \
@@ -36,29 +34,25 @@
               "    char **combined_export;        %p"  "\n"  \
               "    char **combined_nowrap;        %p"  "\n"  \
               "  };"                                   "\n"  \
+              "  capsule_namespace *ns;           %p"  "\n"  \
+              "  {"                                    "\n"  \
+              "    char        *prefix;           %s"  "\n"  \
+              "  };"                                   "\n"  \
               "};"                                     "\n", \
               cap                         ,                  \
               cap->dl_handle              ,                  \
-              cap->prefix                 ,                  \
               cap->meta                   ,                  \
               cap->meta->namespace        ,                  \
               cap->meta->soname           ,                  \
               cap->meta->default_prefix   ,                  \
-              cap->meta->active_prefix    ,                  \
               cap->meta->exclude          ,                  \
               cap->meta->export           ,                  \
               cap->meta->nowrap           ,                  \
               cap->meta->combined_exclude ,                  \
               cap->meta->combined_export  ,                  \
-              cap->meta->combined_nowrap  ); })
-
-typedef struct _capsule_namespace
-{
-    const char *prefix;
-    ptr_list *exclusions;
-    ptr_list *exports;
-    ptr_list *nowrap;
-} capsule_namespace;
+              cap->meta->combined_nowrap  ,                  \
+              cap->ns                     ,                  \
+              cap->ns->prefix             ); })
 
 static ptr_list *namespaces = NULL;
 
@@ -77,11 +71,19 @@ static int str_equal (const void *a, const void *b)
     return strcmp( (char *)a, (char *)b ) == 0;
 }
 
+static const char *get_prefix_nocopy (const char *dflt, const char *soname);
+
 static capsule_namespace *
-get_namespace (const char *prefix)
+get_namespace (const char *default_prefix, const char *soname)
 {
+    const char *prefix = get_prefix_nocopy( default_prefix, soname );
     capsule_namespace *ns;
 
+    // Normalize so that libraries with prefix NULL, "" or "/" are all
+    // treated as equivalent
+    if( prefix == NULL || prefix[0] == '\0' )
+        prefix = "/";
+
     if( namespaces == NULL )
         namespaces = ptr_list_alloc( 4 );
 
@@ -96,7 +98,7 @@ get_namespace (const char *prefix)
     }
 
     ns = calloc( 1, sizeof(capsule_namespace) );
-    ns->prefix      = prefix;
+    ns->prefix      = strdup( prefix );
     ns->exclusions  = ptr_list_alloc( 4 );
     ns->exports     = ptr_list_alloc( 4 );
     ns->nowrap      = ptr_list_alloc( 4 );
@@ -166,22 +168,16 @@ get_capsule_metadata (struct link_map *map, const char *only)
         meta->namespace = LM_ID_NEWLM;
         meta->closed    = 0;
 
-        if( meta->active_prefix )
-            free( meta->active_prefix );
-
-        meta->active_prefix =
-          capsule_get_prefix( meta->default_prefix, meta->soname );
-
         cap = meta->handle;
 
         if( cap == NULL )
         {
             cap = xcalloc( 1, sizeof(struct _capsule) );
+            cap->ns = get_namespace( meta->default_prefix, meta->soname );
             DEBUG( DEBUG_CAPSULE,
                    "Creating new capsule %p for metadata %p (%s … %s)",
-                   cap, meta, meta->active_prefix, meta->soname );
+                   cap, meta, cap->ns->prefix, meta->soname );
             cap->meta = meta;
-            cap->prefix = meta->active_prefix;
             cap->seen.all  = ptr_list_alloc( 32 );
             cap->seen.some = ptr_list_alloc( 32 );
             meta->handle = cap;
@@ -190,7 +186,7 @@ get_capsule_metadata (struct link_map *map, const char *only)
 
         DEBUG( DEBUG_CAPSULE,
                "found metadata for %s … %s at %p (capsule: %p)",
-               meta->active_prefix, meta->soname, meta, cap );
+               cap->ns->prefix, meta->soname, meta, cap );
         break;
     }
 }
@@ -280,11 +276,9 @@ update_metadata (const char *match)
         if( !cap )
             continue;
 
-        capsule_namespace *ns = get_namespace( cap->prefix );
-
-        add_new_strings_to_ptrlist( ns->exclusions, cap->meta->exclude );
-        add_new_strings_to_ptrlist( ns->exports,    cap->meta->export  );
-        add_new_strings_to_ptrlist( ns->nowrap,     cap->meta->nowrap  );
+        add_new_strings_to_ptrlist( cap->ns->exclusions, cap->meta->exclude );
+        add_new_strings_to_ptrlist( cap->ns->exports,    cap->meta->export  );
+        add_new_strings_to_ptrlist( cap->ns->nowrap,     cap->meta->nowrap  );
     }
 
     // now squash the meta data ptr_lists into char** that
@@ -296,15 +290,13 @@ update_metadata (const char *match)
         if( !cap )
             continue;
 
-        capsule_namespace *ns = get_namespace( cap->prefix );
-
         free_strv( cap->meta->combined_exclude );
         free_strv( cap->meta->combined_export  );
         free_strv( cap->meta->combined_nowrap  );
 
-        cap->meta->combined_exclude = cook_list( ns->exclusions );
-        cap->meta->combined_export  = cook_list( ns->exports );
-        cap->meta->combined_nowrap  = cook_list( ns->nowrap );
+        cap->meta->combined_exclude = cook_list( cap->ns->exclusions );
+        cap->meta->combined_export  = cook_list( cap->ns->exports );
+        cap->meta->combined_nowrap  = cook_list( cap->ns->nowrap );
     }
 }
 
@@ -340,11 +332,22 @@ static void __attribute__ ((constructor)) _init_capsule (void)
 
 char *
 capsule_get_prefix (const char *dflt, const char *soname)
+{
+    const char *prefix = get_prefix_nocopy( dflt, soname );
+
+    if (prefix != NULL)
+        return xstrdup( prefix );
+
+    return NULL;
+}
+
+static const char *
+get_prefix_nocopy (const char *dflt, const char *soname)
 {
     char env_var[PATH_MAX] = CAP_ENV_PREFIX;
     const size_t offs = strlen( CAP_ENV_PREFIX );
     size_t x = 0;
-    char *prefix = NULL;
+    const char *prefix = NULL;
 
     for( ; (x < strlen(soname)) && (x + offs < PATH_MAX); x++ )
     {
@@ -360,7 +363,7 @@ capsule_get_prefix (const char *dflt, const char *soname)
     if( (prefix = secure_getenv( &env_var[0] )) )
     {
         DEBUG( DEBUG_SEARCH, "Capsule prefix is %s: %s", &env_var[0], prefix );
-        return strdup( prefix );
+        return prefix;
     }
 
     DEBUG( DEBUG_CAPSULE, "checking %s\n", CAP_ENV_PREFIX "PREFIX" );
@@ -368,13 +371,13 @@ capsule_get_prefix (const char *dflt, const char *soname)
     {
         DEBUG( DEBUG_SEARCH, "Capsule prefix is "CAP_ENV_PREFIX"PREFIX: %s",
                prefix );
-        return strdup( prefix );
+        return prefix;
     }
 
     if( dflt )
     {
         DEBUG( DEBUG_SEARCH, "Capsule prefix is built-in: %s", dflt );
-        return strdup( dflt );
+        return dflt;
     }
 
     DEBUG( DEBUG_SEARCH, "Capsule prefix is missing" );
@@ -471,7 +474,6 @@ capsule_close (capsule cap)
     CLEAR( free_strv, meta->combined_exclude );
     CLEAR( free_strv, meta->combined_export  );
     CLEAR( free_strv, meta->combined_nowrap  );
-    CLEAR( free     , meta->active_prefix    );
     meta->handle = NULL;
 
     CLEAR( ptr_list_free, cap->seen.all  );
diff --git a/capsule/capsule-private.h b/capsule/capsule-private.h
index 5ef4865a3..4640fa2da 100644
--- a/capsule/capsule-private.h
+++ b/capsule/capsule-private.h
@@ -6,13 +6,21 @@
 typedef void * (*dlsymfunc) (void *handle, const char *symbol);
 typedef void * (*dlopnfunc) (const char *file, int flags);
 
+typedef struct _capsule_namespace
+{
+    const char *prefix;
+    ptr_list *exclusions;
+    ptr_list *exports;
+    ptr_list *nowrap;
+} capsule_namespace;
+
 struct _capsule
 {
     void  *dl_handle;
-    const char *prefix;
     capsule_item *relocations;
     struct { ptr_list *all; ptr_list *some; } seen;
     capsule_metadata *meta;
+    capsule_namespace *ns;
 };
 
 extern ptr_list *_capsule_list;
diff --git a/capsule/capsule-wrappers.c b/capsule/capsule-wrappers.c
index e943af803..855a5fe17 100644
--- a/capsule/capsule-wrappers.c
+++ b/capsule/capsule-wrappers.c
@@ -182,12 +182,12 @@ capsule_shim_dlopen(const capsule cap, const char *file, int flag)
 
     DEBUG( DEBUG_WRAPPERS|DEBUG_DLFUNC,
            "dlopen(%s, %x) wrapper: LMID: %ld; prefix: %s;",
-           file, flag, cap->meta->namespace, cap->meta->active_prefix );
+           file, flag, cap->meta->namespace, cap->ns->prefix );
 
-    if( cap->prefix && strcmp(cap->prefix, "/") )
+    if( cap->ns->prefix && strcmp(cap->ns->prefix, "/") )
     {
         if( !ld_libs_init( &ldlibs, (const char **)cap->meta->combined_exclude,
-                           cap->prefix, debug_flags, &code, &errors ) )
+                           cap->ns->prefix, debug_flags, &code, &errors ) )
         {
             DEBUG( DEBUG_LDCACHE|DEBUG_WRAPPERS|DEBUG_DLFUNC,
                    "Initialising ld_libs data failed: error %d: %s",
@@ -198,7 +198,7 @@ capsule_shim_dlopen(const capsule cap, const char *file, int flag)
         if( !ld_libs_load_cache( &ldlibs, "/etc/ld.so.cache", &code, &errors ) )
         {
             DEBUG( DEBUG_LDCACHE|DEBUG_WRAPPERS|DEBUG_DLFUNC,
-                   "Loading ld.so.cache from %s: error %d: %s", cap->prefix,
+                   "Loading ld.so.cache from %s: error %d: %s", cap->ns->prefix,
                    code, errors );
             goto cleanup;
         }
@@ -208,7 +208,7 @@ capsule_shim_dlopen(const capsule cap, const char *file, int flag)
         {
             DEBUG( DEBUG_SEARCH|DEBUG_WRAPPERS|DEBUG_DLFUNC,
                            "Not found: %s under %s: error %d: %s",
-                           file, cap->prefix, code, errors );
+                           file, cap->ns->prefix, code, errors );
             goto cleanup;
         }
 
diff --git a/capsule/capsule.h b/capsule/capsule.h
index b545412a4..7ace8e424 100644
--- a/capsule/capsule.h
+++ b/capsule/capsule.h
@@ -102,7 +102,6 @@ struct _capsule_metadata
     const int     capsule_abi;
     /*< private >*/
     int     closed;
-    char   *active_prefix;
     char  **combined_exclude;
     char  **combined_export;
     char  **combined_nowrap;
-- 
GitLab