From 9a983db35c09028386bf968e3863d17f497a5a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vivek=20Das=C2=A0Mohapatra?= <vivek@collabora.co.uk> Date: Mon, 30 Oct 2017 16:30:03 +0000 Subject: [PATCH] capsule: rework the handle infrastructure to allow multiple capsules Define a capsule mete-data struct which can be declared globally per-proxy to allow libcapsule to manage a set of capsules and merge them into one namespace if they share a /host prefix. This allows us to have one capsule per proxied library, each with the correct soname instead of one monolithic blob capsule which can only have one soname. Conflicts: capsule/capsule-dlmopen.c capsule/capsule-init.c capsule/capsule-wrappers.c --- capsule/capsule-dlmopen.c | 66 ++++++- capsule/capsule-init.c | 390 +++++++++++++++++++++++++++++++++++-- capsule/capsule-private.h | 4 +- capsule/capsule-wrappers.c | 79 +++++--- capsule/capsule.h | 118 ++++++++--- 5 files changed, 593 insertions(+), 64 deletions(-) diff --git a/capsule/capsule-dlmopen.c b/capsule/capsule-dlmopen.c index 7e3546a9b..95ac4175c 100644 --- a/capsule/capsule-dlmopen.c +++ b/capsule/capsule-dlmopen.c @@ -241,8 +241,62 @@ capsule_load (const capsule cap, { void *ret = NULL; ld_libs_t ldlibs = {}; + capsule_metadata *cm = NULL; + + // if we were passed a default new-namespace flag see + // if we've already established a namespace for this + // filesystem prefix in the global cache and use that: + DEBUG( DEBUG_CAPSULE, "requested namespace %ld for %s (newlm: %d)", + *namespace, dso, LM_ID_NEWLM ); + if( *namespace == LM_ID_NEWLM ) + { + // first fetch the subcapsule metadata for this specific + // target DSO if it exists: + for( size_t n = 0; n < capsule_manifest->next; n++ ) + { + capsule_metadata *m = ptr_list_nth_ptr( capsule_manifest, n ); + DEBUG( DEBUG_CAPSULE, "checking metadata %d for %p, %s", + n, m, m ? m->soname : "---" ); + + if( !m || strcmp( dso, m->soname ) ) + continue; + + cm = m; + break; + } + + DEBUG( DEBUG_CAPSULE, "metadata %p found for %s (LM: %ld)", + cm, cm->soname, cm->namespace ); + + // next, if we have subcapsule metadata, see if there's + // a Lmid_t value alrady allocated for it: + if( cm && cm->namespace == LM_ID_NEWLM ) + for( size_t n = 0; n < capsule_manifest->next; n++ ) + { + capsule_metadata *m = ptr_list_nth_ptr( capsule_manifest, n ); + + // this subcapsule is for a different prefix. skip it: + //DEBUG( DEBUG_CAPSULE, "checking prefix match: %p vs %p", + // cap->prefix, m->active_prefix ); + if( strcmp( cap->prefix, m->active_prefix ) ) + continue; + + // we found a pre-allocated Lmid_t. Use it: + if( m->namespace != LM_ID_NEWLM ) + { + DEBUG( DEBUG_CAPSULE, "re-using LM: %ld from %s", + m->namespace, m->soname ); + *namespace = cm->namespace = m->namespace; + break; + } + } + } + + ld_libs_init( &ldlibs, + (const char **) cap->meta->combined_exclude, + cap->meta->active_prefix, debug_flags, errcode, error ); - if( !ld_libs_init( &ldlibs, cap->exclude, cap->prefix, debug_flags, errcode, error ) ) + if( errcode && *errcode ) return NULL; // ================================================================== @@ -273,7 +327,11 @@ capsule_load (const capsule cap, // ================================================================== // load the stack of DSOs we need: ret = ld_libs_load( &ldlibs, namespace, 0, errcode, error ); - cap->namespace = *namespace; + + cap->meta->namespace = *namespace; + + if( cm ) + cm->namespace = *namespace; if( debug_flags & DEBUG_CAPSULE ) { @@ -287,7 +345,9 @@ capsule_load (const capsule cap, // TODO: failure in the dlopen fixup phase should probably be fatal: if( ret != NULL && // no errors so far wrappers != NULL ) // have a dlopen fixup function - install_wrappers( ret, wrappers, cap->exclude, errcode, error ); + install_wrappers( ret, wrappers, + (const char **)cap->meta->combined_exclude, + errcode, error ); cap->dl_handle = ret; diff --git a/capsule/capsule-init.c b/capsule/capsule-init.c index 85f1f9d16..767d0dcb4 100644 --- a/capsule/capsule-init.c +++ b/capsule/capsule-init.c @@ -2,40 +2,408 @@ #include "capsule/capsule-private.h" #include "utils/utils.h" #include <stdlib.h> +#include <stdio.h> #include <dlfcn.h> +#include <string.h> +#include <ctype.h> +#include <sys/param.h> + +#define CAP_ENV_PREFIX "CAPSULE_" + +#define DUMP_STRV(what, css) \ + ({ int _i = 0; for( char **_c = css; _c && *_c; _c++, _i++ ) \ + DEBUG( DEBUG_CAPSULE, " ->%s[ %02d ]: %s", #what, _i, *_c ); }) + +#define DUMP_METADATA(x,m) ({ \ + DEBUG( DEBUG_CAPSULE, "\nMETADATA #%d\n", x ); \ + DEBUG( DEBUG_CAPSULE, " \n" \ + "struct _capsule_metadata %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" \ + " char **combined_exclude; %p" "\n" \ + " char **combined_export; %p" "\n" \ + " char **combined_nowrap; %p" "\n" \ + "};" "\n", \ + m, \ + m->namespace , \ + m->soname , \ + m->default_prefix , \ + m->active_prefix , \ + m->exclude , \ + m->export , \ + m->nowrap , \ + m->combined_exclude , \ + m->combined_export , \ + m->combined_nowrap ); }) + +typedef struct _tree_data +{ + const char *prefix; + ptr_list *list; +} tree_data; + +static ptr_list *tree_exclusions = NULL; +static ptr_list *tree_exports = NULL; +static ptr_list *tree_nowrap = NULL; + +ptr_list *capsule_manifest = NULL; dlsymfunc capsule_dl_symbol = NULL; dlopnfunc capsule_dl_open = NULL; +static int ptr_equal (const void *a, const void *b) +{ + return (a == b) ? 1 : 0; +} + +static int str_equal (const void *a, const void *b) +{ + if( a == b ) + return 1; + + if( !a || !b ) + return 0; + + return strcmp( (char *)a, (char *)b ) == 0; +} + +static tree_data * +get_prefix_data (const char *prefix, ptr_list **cache) +{ + tree_data *td; + + if( *cache == NULL ) + *cache = ptr_list_alloc( 4 ); + + for( size_t x = 0; x < (*cache)->next; x++ ) + { + td = ptr_list_nth_ptr( *cache, x ); + + if( !td || strcmp( prefix, td->prefix ) ) + continue; + + return td; + } + + td = calloc( 1, sizeof(tree_data) ); + + td->prefix = prefix; + td->list = ptr_list_alloc( 4 ); + + ptr_list_push_ptr( *cache, td ); + + return td; +} + +static tree_data * +get_excludes (const char *prefix) +{ + return get_prefix_data( prefix, &tree_exclusions ); +} + +static tree_data * +get_exports (const char *prefix) +{ + return get_prefix_data( prefix, &tree_exports ); +} + +static tree_data * +get_nowrap (const char *prefix) +{ + return get_prefix_data( prefix, &tree_nowrap ); +} + +static void +get_capsule_metadata (struct link_map *map, ptr_list *info, const char *only) +{ + ElfW(Addr) base = map->l_addr; + ElfW(Dyn) *dyn = map->l_ld; + ElfW(Dyn) *entry; + ElfW(Sym) *symbol; + + const void *strtab = NULL; + const void *symtab = NULL; + + if( map->l_name == NULL || *map->l_name == '\0' ) + return; + + for( entry = dyn; entry->d_tag != DT_NULL; entry++ ) + { + switch( entry->d_tag ) + { + case DT_SYMTAB: + symtab = (const void *) fix_addr( (void *)base, entry->d_un.d_ptr ); + break; + + case DT_STRTAB: + strtab = (const void *) fix_addr( (void *)base, entry->d_un.d_ptr ); + break; + + default: + break; + } + } + + if( !strtab || !symtab ) + return; + + for( symbol = (ElfW(Sym) *)symtab; + ( (ELFW_ST_TYPE(symbol->st_info) < STT_NUM) && + (ELFW_ST_BIND(symbol->st_info) < STB_NUM) ); + symbol++ ) + { + capsule_metadata *meta = NULL; + char *name = (char *)strtab + symbol->st_name; + + if( !name || strcmp( "capsule_meta", name ) ) + continue; + + meta = (capsule_metadata *)fix_addr( (void *)base, symbol->st_value ); + + // if we were asked for a specific soname's meta data then ignore + // everything else: + if( only && strcmp( only, meta->soname ) ) + continue; + + meta->namespace = LM_ID_NEWLM; + + if( meta->active_prefix ) + free( meta->active_prefix ); + + meta->active_prefix = + capsule_get_prefix( meta->default_prefix, meta->soname ); + + ptr_list_add_ptr( info, meta, ptr_equal ); + DEBUG( DEBUG_CAPSULE, "found metatdata for %s … %s at %p", + meta->active_prefix, meta->soname, meta ); + break; + } +} + +static char ** +cook_list (tree_data *tx) +{ + char **cooked = calloc( tx->list->next + 1, sizeof(char *) ); + + for( size_t j = 0; j < tx->list->next; j++ ) + *(cooked + j) = (char *)ptr_list_nth_ptr( tx->list, j ); + + *(cooked + tx->list->next) = NULL; + + return cooked; +} + +static void +add_new_strings_to_ptrlist (ptr_list *list, const char **strings) +{ + for( char **c = (char **)strings; c && *c; c++ ) + ptr_list_add_ptr( list, *c, str_equal ); +} + +static void +free_strv (char **strv) +{ + if( !strv ) + return; + + free( strv ); +} + +static void +update_metadata (const char *match) +{ + struct link_map *map; + void *handle; + + handle = dlmopen( LM_ID_BASE, NULL, RTLD_LAZY|RTLD_NOLOAD ); + dlinfo( handle, RTLD_DI_LINKMAP, &map ); + + // we're not guaranteed to be at the start of the link map chain: + while( map->l_prev ) + map = map->l_prev; + + // pick up any capsule metadata we can see: + // if the soname (match) is NULL, this means _all_ metadata, + // otherwise just the metadata that is string-equal: + if (map->l_next) + for( struct link_map *m = map; m; m = m->l_next ) + get_capsule_metadata( m, capsule_manifest, match ); + + // merge the string lists for each active prefix: + // ie all excludes for /host should be in one exclude list, + // all nowrap entries for /host should bein another list, all + // excludes for /badgerbadger should be in another, etc etc: + for( size_t i = 0; i < capsule_manifest->next; i++ ) + { + capsule_metadata *cm = ptr_list_nth_ptr( capsule_manifest, i ); + tree_data *tx = get_excludes( cm->active_prefix ); + tree_data *te = get_exports ( cm->active_prefix ); + tree_data *tn = get_nowrap ( cm->active_prefix ); + + add_new_strings_to_ptrlist( tx->list, cm->exclude ); + add_new_strings_to_ptrlist( te->list, cm->export ); + add_new_strings_to_ptrlist( tn->list, cm->nowrap ); + } + + // now squash the meta data ptr_lists into char** that + // the underlying infrastructure actually uses: + for( size_t i = 0; i < capsule_manifest->next; i++ ) + { + capsule_metadata *cm = ptr_list_nth_ptr( capsule_manifest, i ); + tree_data *tx = get_excludes( cm->active_prefix ); + tree_data *te = get_exports ( cm->active_prefix ); + tree_data *tn = get_nowrap ( cm->active_prefix ); + + free_strv( cm->combined_exclude ); + free_strv( cm->combined_export ); + free_strv( cm->combined_nowrap ); + + cm->combined_exclude = cook_list( tx ); + cm->combined_export = cook_list( te ); + cm->combined_nowrap = cook_list( tn ); + } +} + static void __attribute__ ((constructor)) _init_capsule (void) { + capsule_manifest = ptr_list_alloc( 16 ); + + set_debug_flags( secure_getenv("CAPSULE_DEBUG") ); + + update_metadata( NULL ); + capsule_dl_symbol = dlsym( RTLD_DEFAULT, "dlsym" ); capsule_dl_open = dlsym( RTLD_DEFAULT, "dlopen" ); + if( !(debug_flags & DEBUG_CAPSULE) ) + return; + + for( unsigned int x = 0; x < capsule_manifest->next; x++ ) + { + capsule_metadata *cm = capsule_manifest->loc[ x ].ptr; + const char **soname = cm->exclude; + + DEBUG( DEBUG_CAPSULE, "[%02d] %s metadata:\n", x, cm->soname ); + + while( soname && *soname ) + fprintf( stderr, " %s\n", *(soname++) ); + } +} + +char * +capsule_get_prefix (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; + + for( ; (x < strlen(soname)) && (x + offs < PATH_MAX); x++ ) + { + char c = *(soname + x); + + env_var[ x + offs ] = isalnum( c ) ? toupper( c ) : '_'; + } + + safe_strncpy( &env_var[ x + offs ], "_PREFIX", PATH_MAX - (x + offs + 1) ); + env_var[ PATH_MAX - 1 ] = '\0'; + + fprintf(stderr, "checking %s\n", &env_var[0] ); + if( (prefix = secure_getenv( &env_var[0] )) ) + { + DEBUG( DEBUG_SEARCH, "Capsule prefix is %s: %s", &env_var[0], prefix ); + return strdup( prefix ); + } + + fprintf(stderr, "checking %s\n", CAP_ENV_PREFIX "PREFIX" ); + if( (prefix = secure_getenv( CAP_ENV_PREFIX "PREFIX" )) ) + { + DEBUG( DEBUG_SEARCH, "Capsule prefix is "CAP_ENV_PREFIX"PREFIX: %s", + prefix ); + return strdup( prefix ); + } + + if( dflt ) + { + DEBUG( DEBUG_SEARCH, "Capsule prefix is built-in: %s", dflt ); + return strdup( dflt ); + } + + DEBUG( DEBUG_SEARCH, "Capsule prefix is missing" ); + return NULL; } +static capsule_metadata * +get_cached_metadata (const char *soname) +{ + size_t i = 0; + capsule_metadata *meta = NULL; + + for( size_t n = 0; n < capsule_manifest->next; n++ ) + { + capsule_metadata *cm = ptr_list_nth_ptr( capsule_manifest, n ); + + if( !cm || strcmp( cm->soname, soname ) ) + continue; + + i = n; + meta = cm; + break; + } + + if(meta) + DUMP_METADATA(i, meta); + + return meta; +} capsule -capsule_init (Lmid_t namespace, - const char *prefix, - const char **exclude, - const char **exported) +capsule_init (const char *soname) { capsule handle = xcalloc( 1, sizeof(struct _capsule) ); + capsule_metadata *meta = NULL; - set_debug_flags( secure_getenv("CAPSULE_DEBUG") ); + meta = get_cached_metadata( soname ); - handle->namespace = namespace; - handle->prefix = prefix; - handle->exclude = exclude; - handle->exported = exported; + if( !meta ) + { + DEBUG( DEBUG_CAPSULE, "no metadata for %s registered: " + "may be a dlopened capsule", soname ); + DEBUG( DEBUG_CAPSULE, "updating capsule metadata" ); + update_metadata( soname ); + meta = get_cached_metadata( soname ); + } + if( meta ) + { + handle->prefix = meta->active_prefix; + + for( size_t i = 0; i < capsule_manifest->next; i++ ) + { + capsule_metadata *cm = ptr_list_nth_ptr( capsule_manifest, i ); + DEBUG( DEBUG_CAPSULE, " "); + DUMP_METADATA( i, cm ); + DUMP_STRV( excluded, cm->combined_exclude ); + DUMP_STRV( exported, cm->combined_export ); + DUMP_STRV( nowrap, cm->combined_nowrap ); + } + } // in principle we should be able to make both reloc calls // efficient in the same do-not-redo-your-work way, but for // some reason the unrestricted relocation breaks if we turn // this one on. setting the tracker to NULL disables for now. - handle->seen.all = NULL; + handle->seen.all = ptr_list_alloc( 32 ); handle->seen.some = ptr_list_alloc( 32 ); + // poke the initialised metadata back into the handle + // and vice versa: + handle->meta = meta; + meta->handle = handle; + return handle; } - diff --git a/capsule/capsule-private.h b/capsule/capsule-private.h index 6b85e3ef8..9602ccc32 100644 --- a/capsule/capsule-private.h +++ b/capsule/capsule-private.h @@ -8,13 +8,11 @@ typedef void * (*dlopnfunc) (const char *file, int flags); struct _capsule { - Lmid_t namespace; void *dl_handle; const char *prefix; - const char **exclude; // list of DSOs _not_ to install in the capsule - const char **exported; // list of DSOs from which to export capsule_item *relocations; struct { ptr_list *all; ptr_list *some; } seen; + capsule_metadata *meta; }; extern ptr_list *capsule_manifest; diff --git a/capsule/capsule-wrappers.c b/capsule/capsule-wrappers.c index d0384fa97..b163c8fbf 100644 --- a/capsule/capsule-wrappers.c +++ b/capsule/capsule-wrappers.c @@ -10,9 +10,9 @@ #include <errno.h> static int -dso_is_exported (const char *dsopath, const char **exported) +dso_is_exported (const char *dsopath, char **exported) { - for( const char **ex = exported; ex && *ex; ex++ ) + for( char **ex = exported; ex && *ex; ex++ ) if( soname_matches_path( *ex, dsopath ) ) return 1; @@ -20,20 +20,35 @@ dso_is_exported (const char *dsopath, const char **exported) } void * -capsule_external_dlsym (capsule cap, void *handle, const char *symbol) +capsule_external_dlsym (void *handle, const char *symbol) { DEBUG( DEBUG_DLFUNC|DEBUG_WRAPPERS, "dlsym(%s)", symbol ); void *addr = NULL; - if( addr ) + for( size_t n = 0; n < capsule_manifest->next; n++ ) { - Dl_info dso = { 0 }; + capsule_metadata *m = ptr_list_nth_ptr( capsule_manifest, n ); + addr = capsule_dl_symbol ( m->handle->dl_handle, symbol ); - // only keep addr from the capsule if it's from an exported DSO: - // or if we are unable to determine where it came from (what?) - if( dladdr( addr, &dso ) ) - if( !dso_is_exported( dso.dli_fname, cap->exported ) ) - addr = NULL; + if( addr ) + { + Dl_info dso = { 0 }; + + // only keep addr from the capsule if it's from an exported DSO: + // or if we are unable to determine where it came from (what?) + if( dladdr( addr, &dso ) ) + { + if( !dso_is_exported( dso.dli_fname, m->combined_export ) ) + addr = NULL; + + DEBUG( DEBUG_DLFUNC|DEBUG_WRAPPERS, + "symbol %s is from soname %s - %s", + symbol, dso.dli_fname, addr ? "OK" : "Ignored" ); + + if( addr ) + break; + } + } } if( addr == NULL ) @@ -47,7 +62,7 @@ capsule_external_dlsym (capsule cap, void *handle, const char *symbol) } void * -capsule_external_dlopen(const capsule cap, const char *file, int flag) +capsule_external_dlopen(const char *file, int flag) { void *handle = NULL; char *error = NULL; @@ -70,11 +85,30 @@ capsule_external_dlopen(const capsule cap, const char *file, int flag) debug_flags = DEBUG_RELOCS|DEBUG_SEARCH; // This may not even be necessary, so it should not be fatal. // We do want to log it though as it might be an important clue: - if( capsule_relocate( cap, NULL, &error ) != 0 ) + for( size_t n = 0; n < capsule_manifest->next; n++ ) { - fprintf( stderr, "relocation after dlopen(%s, …) failed: %s\n", - file, error ); - free( error ); + capsule_metadata *m = ptr_list_nth_ptr( capsule_manifest, n ); + const capsule c = m->handle; + + if( capsule_relocate( c, NULL, &error ) != 0 ) + { + fprintf( stderr, + "relocation from %s after dlopen(%s, …) failed: %s\n", + m->soname, file, error ); + free( error ); + } + + if( capsule_relocate_except( c, + m->dl_wrappers, + (const char **)m->combined_nowrap, + &error ) != 0 ) + { + fprintf( stderr, + "dl-wrapper relocation from %s after " + "dlopen(%s, …) failed: %s\n", + m->soname, file, error ); + free( error ); + } } debug_flags = df; @@ -93,17 +127,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->namespace, cap->prefix ); + file, flag, cap->meta->namespace, cap->meta->active_prefix ); if( cap->prefix && strcmp(cap->prefix, "/") ) { - if( !ld_libs_init( &ldlibs, cap->exclude, cap->prefix, debug_flags, - &code, &errors ) ) - { - DEBUG( DEBUG_LDCACHE|DEBUG_WRAPPERS|DEBUG_DLFUNC, - "ld_libs_init: error %d: %s", code, errors ); - goto cleanup; - } + ld_libs_init( &ldlibs, (const char **)cap->meta->combined_exclude, + cap->prefix, debug_flags, &code, &errors ); if( !ld_libs_load_cache( &ldlibs, "/etc/ld.so.cache", &code, &errors ) ) { @@ -131,7 +160,7 @@ capsule_shim_dlopen(const capsule cap, const char *file, int flag) } // load them up in reverse dependency order: - res = ld_libs_load( &ldlibs, &cap->namespace, flag, &code, &errors ); + res = ld_libs_load( &ldlibs, &cap->meta->namespace, flag, &code, &errors ); if( !res ) DEBUG( DEBUG_WRAPPERS|DEBUG_DLFUNC, @@ -141,7 +170,7 @@ capsule_shim_dlopen(const capsule cap, const char *file, int flag) } else // no prefix: straightforward dlmopen into our capsule namespace: { - res = dlmopen( cap->namespace, file, flag ); + res = dlmopen( cap->meta->namespace, file, flag ); if( !res ) DEBUG( DEBUG_WRAPPERS|DEBUG_DLFUNC, diff --git a/capsule/capsule.h b/capsule/capsule.h index f8cb4157b..3baa512c2 100644 --- a/capsule/capsule.h +++ b/capsule/capsule.h @@ -68,29 +68,57 @@ struct _capsule_item }; /** - * capsule_init: - * @namespace: An #Lmid_t value. (usually %LM_ID_NEWLM) - * @prefix: The mount point of the foreign tree in wich to find DSOs + * capsule_metadata: + * @namespace: #Lmid_t value for the namespace used for this capsule + * @soname: The soname of the encapsulated library + * @default_prefix: The default root location of the filesystem from which the + * encapsulated library should be loaded * @exclude: (array zero-terminated=1): an array of char *, each * specifying a DSO not to load, terminated by a %NULL entry - * @exported: An array of DSO names considered to ba valid symbol sources + * @export: (array zero-terminated=1): an array of char *, each + * specifying a DSO whose symbols should be exported from this + * capsule + * @nowrap: (array zero-terminated=1): an array of char *, each specifying + * a DSO whose dlopen() implementation should _not_ be wrapped + * should typically contain the libc cluster and the capsule proxy + * library itself + * + * This struct allows libcapsule proxy libraries to statically declare + * metadata about themselves that libcapsule needs at link time in order + * to function properly. + */ +typedef struct _capsule_metadata capsule_metadata; + +struct _capsule_metadata +{ + /*< public >*/ + Lmid_t namespace; + const char *soname; + const char *default_prefix; + const char **exclude; + const char **export; + const char **nowrap; + capsule_item *dl_wrappers; + /*< private >*/ + char *active_prefix; + char **combined_exclude; + char **combined_export; + char **combined_nowrap; + capsule handle; +}; + +/** + * capsule_init: + * @soname: the soname of the target library * * Returns: a #capsule handle. * * Does any initialisation necessary to use libcapsule's functions. * Currently just initialises the debug flags from the CAPSULE_DEBUG * environment variable. - * - * The #Lmid_t value @namespace should normally be %LM_ID_NEWLM - * to create a new namespace. - * - * An empty ("") or void (%NULL) @prefix is equivalent to "/". */ _CAPSULE_PUBLIC -capsule capsule_init (Lmid_t namespace, - const char *prefix, - const char **exclude, - const char **exported); +capsule capsule_init (const char *soname); /** * capsule_relocate: @@ -230,7 +258,6 @@ void *capsule_shim_dlopen(const capsule capsule, const char *file, int flag); /** * capsule_external_dlsym: - * @cap: A dl handle as returned by capsule_load() * @handle: A dl handle, as passed to dlsym() * @symbol: A symbol name, as passed to dlsym() * @@ -246,17 +273,64 @@ void *capsule_shim_dlopen(const capsule capsule, const char *file, int flag); * * Instead we must intercept dlsym() calls made outside the capsule * and attempt to look for the required symbol in the namespace defined - * by @capsule first - If the required symbol is found there AND is - * from one of the DSO names present in @exported then that symbol is - * returned. If either of those conditions is not met then a normal - * dlsym call with the passed handle is made. + * by the active capsules first - If the required symbol is found there + * AND is from one of the DSO names present in the exported list then that + * symbol is returned. If either of those conditions is not met then + * a normal dlsym call with the passed handle is made. * * This function provides the functionality described above, and is - * intended for use in a suitable wrapper implemented in the the shim - * library. + * normally used automaticaly by libcapsule. It is exposed as API in + * case a libcapsule proxy library needs to do its own specialised + * symbol lookups. + */ +_CAPSULE_PUBLIC +void *capsule_external_dlsym (void *handle, const char *symbol); + +/** + * capsule_external_dlopen: + * @file: A soname, filename or path as passed to dlopen() + * @flag: The dl flags, as per dlopen() + * + * Returns: a void * handle, as per dlopen() + * + * This wrapper is meant to be replace normal calls to dlopen() made by the + * main program or a non-capsule library - it is necessary because en ELF + * object loaded by dlopen() may need us to trigger the capsule_relocate() + * operation in order to make sure its GOT entries are correctly updated. + * + * This wrapper carries out a normal dlopen() and then re-triggers the + * initial capsule_relocate() call immediately, before returning + * the same value that dlopen() would have, given the same @file and @flag + * arguments. */ _CAPSULE_PUBLIC -void *capsule_external_dlsym (capsule cap, void *handle, const char *symbol); +void *capsule_external_dlopen(const char *file, int flag); + +/** + * capsule_get_prefix: + * @dflt: A default capsule prefix path + * @soname: The soname of the library we are encapsulating + * + * Returns: A newly allocated char * pointing to the prefix path + * + * libcapsule provides a proxy to a library, potentially from a foreign + * filesystem tree (found at, for example, ‘/host’). + * + * Since it is useful for this location to be overrideable at startup + * on a per-target-library basis this function standardises the prefix + * selection algorithm as follows: + * + * - An environment variable based on @soname: + * libGL.so.1 would map to CAPSULE_LIBGL_SO_1_PREFIX + * - If that is unset, the CAPSULE_PREFIX environment variable + * - Next: The default to the value passed in @dflt + * - And if all that failed, NULL (which is internally equivalent to "/") + * + * Although the value is newly allocated it will typically be cached + * in a structure that needs to survive the entire lifespan of the + * running program, so freeing it is unlikely to be a concern. + **/ +_CAPSULE_PUBLIC +char *capsule_get_prefix(const char *dflt, const char *soname); _CAPSULE_PUBLIC -void *capsule_external_dlopen(const capsule cap, const char *file, int flag); -- GitLab