Skip to content
Snippets Groups Projects
Commit 7e47ce89 authored by Simon McVittie's avatar Simon McVittie
Browse files

Maintain a list of capsule structures, not a list of capsule_metadata


This enforces the following invariants:

* Capsules and capsule_metadata are related 1:1
* All valid capsules are present in the list
* Only valid capsules are present in the list

Signed-off-by: default avatarSimon McVittie <smcv@collabora.com>
parent e750f608
No related branches found
No related tags found
1 merge request!311Build capsule-capture-libs from a bundled copy of libcapsule
...@@ -252,16 +252,16 @@ capsule_load (const capsule cap, ...@@ -252,16 +252,16 @@ capsule_load (const capsule cap,
{ {
// first fetch the subcapsule metadata for this specific // first fetch the subcapsule metadata for this specific
// target DSO if it exists: // target DSO if it exists:
for( size_t n = 0; n < _capsule_metadata_list->next; n++ ) for( size_t n = 0; n < _capsule_list->next; n++ )
{ {
capsule_metadata *m = ptr_list_nth_ptr( _capsule_metadata_list, n ); capsule other = ptr_list_nth_ptr( _capsule_list, n );
DEBUG( DEBUG_CAPSULE, "checking metadata %d for %p, %s", DEBUG( DEBUG_CAPSULE, "checking metadata %d for %p, %s",
(int) n, m, m ? m->soname : "---" ); (int) n, other, other ? other->meta->soname : "---" );
if( !m || strcmp( dso, m->soname ) ) if( !other || strcmp( dso, other->meta->soname ) )
continue; continue;
cm = m; cm = other->meta;
break; break;
} }
...@@ -271,22 +271,22 @@ capsule_load (const capsule cap, ...@@ -271,22 +271,22 @@ capsule_load (const capsule cap,
// next, if we have subcapsule metadata, see if there's // next, if we have subcapsule metadata, see if there's
// a Lmid_t value alrady allocated for it: // a Lmid_t value alrady allocated for it:
if( cm && cm->namespace == LM_ID_NEWLM ) if( cm && cm->namespace == LM_ID_NEWLM )
for( size_t n = 0; n < _capsule_metadata_list->next; n++ ) for( size_t n = 0; n < _capsule_list->next; n++ )
{ {
capsule_metadata *m = ptr_list_nth_ptr( _capsule_metadata_list, n ); capsule other = ptr_list_nth_ptr( _capsule_list, n );
// this subcapsule is for a different prefix. skip it: // this subcapsule is for a different prefix. skip it:
//DEBUG( DEBUG_CAPSULE, "checking prefix match: %p vs %p", //DEBUG( DEBUG_CAPSULE, "checking prefix match: %p vs %p",
// cap->prefix, m->active_prefix ); // cap->prefix, other->meta->active_prefix );
if( strcmp( cap->prefix, m->active_prefix ) ) if( strcmp( cap->prefix, other->prefix ) )
continue; continue;
// we found a pre-allocated Lmid_t. Use it: // we found a pre-allocated Lmid_t. Use it:
if( m->namespace != LM_ID_NEWLM ) if( other->meta->namespace != LM_ID_NEWLM )
{ {
DEBUG( DEBUG_CAPSULE, "re-using LM: %ld from %s", DEBUG( DEBUG_CAPSULE, "re-using LM: %ld from %s",
m->namespace, m->soname ); other->meta->namespace, other->meta->soname );
*namespace = cm->namespace = m->namespace; *namespace = cm->namespace = other->meta->namespace;
break; break;
} }
} }
......
#include <capsule/capsule.h> #include <capsule/capsule.h>
#include "capsule/capsule-private.h" #include "capsule/capsule-private.h"
#include "utils/utils.h" #include "utils/utils.h"
#include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <dlfcn.h> #include <dlfcn.h>
...@@ -52,15 +54,10 @@ typedef struct _capsule_namespace ...@@ -52,15 +54,10 @@ typedef struct _capsule_namespace
static ptr_list *namespaces = NULL; static ptr_list *namespaces = NULL;
ptr_list *_capsule_metadata_list = NULL; ptr_list *_capsule_list = NULL;
dlsymfunc capsule_dl_symbol = NULL; dlsymfunc capsule_dl_symbol = NULL;
dlopnfunc capsule_dl_open = 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) static int str_equal (const void *a, const void *b)
{ {
if( a == b ) if( a == b )
...@@ -180,9 +177,9 @@ get_capsule_metadata (struct link_map *map, const char *only) ...@@ -180,9 +177,9 @@ get_capsule_metadata (struct link_map *map, const char *only)
cap->seen.all = ptr_list_alloc( 32 ); cap->seen.all = ptr_list_alloc( 32 );
cap->seen.some = ptr_list_alloc( 32 ); cap->seen.some = ptr_list_alloc( 32 );
meta->handle = cap; meta->handle = cap;
ptr_list_push_ptr( _capsule_list, cap );
} }
ptr_list_add_ptr( _capsule_metadata_list, meta, ptr_equal );
DEBUG( DEBUG_CAPSULE, DEBUG( DEBUG_CAPSULE,
"found metadata for %s … %s at %p (capsule: %p)", "found metadata for %s … %s at %p (capsule: %p)",
meta->active_prefix, meta->soname, meta, cap ); meta->active_prefix, meta->soname, meta, cap );
...@@ -268,44 +265,44 @@ update_metadata (const char *match) ...@@ -268,44 +265,44 @@ update_metadata (const char *match)
// ie all excludes for /host should be in one exclude list, // ie all excludes for /host should be in one exclude list,
// all nowrap entries for /host should bein another list, all // all nowrap entries for /host should bein another list, all
// excludes for /badgerbadger should be in another, etc etc: // excludes for /badgerbadger should be in another, etc etc:
for( size_t i = 0; i < _capsule_metadata_list->next; i++ ) for( size_t i = 0; i < _capsule_list->next; i++ )
{ {
capsule_metadata *cm = ptr_list_nth_ptr( _capsule_metadata_list, i ); capsule cap = ptr_list_nth_ptr( _capsule_list, i );
if( !cm || cm->closed ) if( !cap )
continue; continue;
capsule_namespace *ns = get_namespace( cm->active_prefix ); capsule_namespace *ns = get_namespace( cap->prefix );
add_new_strings_to_ptrlist( ns->exclusions, cm->exclude ); add_new_strings_to_ptrlist( ns->exclusions, cap->meta->exclude );
add_new_strings_to_ptrlist( ns->exports, cm->export ); add_new_strings_to_ptrlist( ns->exports, cap->meta->export );
add_new_strings_to_ptrlist( ns->nowrap, cm->nowrap ); add_new_strings_to_ptrlist( ns->nowrap, cap->meta->nowrap );
} }
// now squash the meta data ptr_lists into char** that // now squash the meta data ptr_lists into char** that
// the underlying infrastructure actually uses: // the underlying infrastructure actually uses:
for( size_t i = 0; i < _capsule_metadata_list->next; i++ ) for( size_t i = 0; i < _capsule_list->next; i++ )
{ {
capsule_metadata *cm = ptr_list_nth_ptr( _capsule_metadata_list, i ); capsule cap = ptr_list_nth_ptr( _capsule_list, i );
if( !cm || cm->closed ) if( !cap )
continue; continue;
capsule_namespace *ns = get_namespace( cm->active_prefix ); capsule_namespace *ns = get_namespace( cap->prefix );
free_strv( cm->combined_exclude ); free_strv( cap->meta->combined_exclude );
free_strv( cm->combined_export ); free_strv( cap->meta->combined_export );
free_strv( cm->combined_nowrap ); free_strv( cap->meta->combined_nowrap );
cm->combined_exclude = cook_list( ns->exclusions ); cap->meta->combined_exclude = cook_list( ns->exclusions );
cm->combined_export = cook_list( ns->exports ); cap->meta->combined_export = cook_list( ns->exports );
cm->combined_nowrap = cook_list( ns->nowrap ); cap->meta->combined_nowrap = cook_list( ns->nowrap );
} }
} }
static void __attribute__ ((constructor)) _init_capsule (void) static void __attribute__ ((constructor)) _init_capsule (void)
{ {
_capsule_metadata_list = ptr_list_alloc( 16 ); _capsule_list = ptr_list_alloc( 16 );
set_debug_flags( secure_getenv("CAPSULE_DEBUG") ); set_debug_flags( secure_getenv("CAPSULE_DEBUG") );
...@@ -317,16 +314,16 @@ static void __attribute__ ((constructor)) _init_capsule (void) ...@@ -317,16 +314,16 @@ static void __attribute__ ((constructor)) _init_capsule (void)
if( !(debug_flags & DEBUG_CAPSULE) ) if( !(debug_flags & DEBUG_CAPSULE) )
return; return;
for( unsigned int x = 0; x < _capsule_metadata_list->next; x++ ) for( unsigned int x = 0; x < _capsule_list->next; x++ )
{ {
capsule_metadata *cm = _capsule_metadata_list->loc[ x ].ptr; capsule cap = _capsule_list->loc[ x ].ptr;
if( !cm || cm->closed ) if( !cap )
continue; continue;
const char **soname = cm->exclude; const char **soname = cap->meta->exclude;
DEBUG( DEBUG_CAPSULE, "[%02d] %s metadata:\n", x, cm->soname ); DEBUG( DEBUG_CAPSULE, "[%02d] %s metadata:\n", x, cap->meta->soname );
while( soname && *soname ) while( soname && *soname )
fprintf( stderr, " %s\n", *(soname++) ); fprintf( stderr, " %s\n", *(soname++) );
...@@ -376,47 +373,42 @@ capsule_get_prefix (const char *dflt, const char *soname) ...@@ -376,47 +373,42 @@ capsule_get_prefix (const char *dflt, const char *soname)
return NULL; return NULL;
} }
static capsule_metadata * static capsule
get_cached_metadata (const char *soname) get_capsule_by_soname (const char *soname)
{ {
size_t i = 0; for( size_t n = 0; n < _capsule_list->next; n++ )
capsule_metadata *meta = NULL;
for( size_t n = 0; n < _capsule_metadata_list->next; n++ )
{ {
capsule_metadata *cm = ptr_list_nth_ptr( _capsule_metadata_list, n ); capsule cap = ptr_list_nth_ptr( _capsule_list, n );
if( !cm || cm->closed || strcmp( cm->soname, soname ) ) if( !cap || strcmp( cap->meta->soname, soname ) )
continue; continue;
i = n; DUMP_METADATA(n, cap->meta);
meta = cm; return cap;
break;
} }
if(meta) return NULL;
DUMP_METADATA(i, meta);
return meta;
} }
capsule capsule
capsule_init (const char *soname) capsule_init (const char *soname)
{ {
capsule_metadata *meta = NULL; capsule cap;
DEBUG( DEBUG_CAPSULE, "Initializing shim library %s", soname );
meta = get_cached_metadata( soname ); cap = get_capsule_by_soname( soname );
if( !meta ) if( !cap )
{ {
DEBUG( DEBUG_CAPSULE, "no metadata for %s registered: " DEBUG( DEBUG_CAPSULE, "no metadata for %s registered: "
"may be a dlopened capsule", soname ); "may be a dlopened capsule", soname );
DEBUG( DEBUG_CAPSULE, "updating capsule metadata" ); DEBUG( DEBUG_CAPSULE, "updating capsule metadata" );
update_metadata( soname ); update_metadata( soname );
meta = get_cached_metadata( soname ); cap = get_capsule_by_soname( soname );
} }
if( !meta ) if( !cap )
{ {
fprintf( stderr, fprintf( stderr,
"libcapsule: %s: Fatal error: cannot initialize shim " "libcapsule: %s: Fatal error: cannot initialize shim "
...@@ -425,21 +417,21 @@ capsule_init (const char *soname) ...@@ -425,21 +417,21 @@ capsule_init (const char *soname)
abort(); abort();
} }
for( size_t i = 0; i < _capsule_metadata_list->next; i++ ) for( size_t i = 0; i < _capsule_list->next; i++ )
{ {
capsule_metadata *cm = ptr_list_nth_ptr( _capsule_metadata_list, i ); capsule other = ptr_list_nth_ptr( _capsule_list, i );
if( !cm || cm->closed ) if( !other )
continue; continue;
DEBUG( DEBUG_CAPSULE, " "); DEBUG( DEBUG_CAPSULE, " ");
DUMP_METADATA( i, cm ); DUMP_METADATA( i, other->meta );
DUMP_STRV( excluded, cm->combined_exclude ); DUMP_STRV( excluded, other->meta->combined_exclude );
DUMP_STRV( exported, cm->combined_export ); DUMP_STRV( exported, other->meta->combined_export );
DUMP_STRV( nowrap, cm->combined_nowrap ); DUMP_STRV( nowrap, other->meta->combined_nowrap );
} }
return meta->handle; return cap;
} }
#define CLEAR(f,x) ({ f( x ); x = NULL; }) #define CLEAR(f,x) ({ f( x ); x = NULL; })
...@@ -449,26 +441,35 @@ capsule_close (capsule cap) ...@@ -449,26 +441,35 @@ capsule_close (capsule cap)
{ {
capsule_metadata *meta = cap->meta; capsule_metadata *meta = cap->meta;
DEBUG( DEBUG_CAPSULE, "Uninitializing shim library %s", meta->soname );
// scrub all entries in the manifest pointing to this metadata
for( size_t n = 0; n < _capsule_list->next; n++ )
{
capsule other = ptr_list_nth_ptr( _capsule_list, n );
if( other == cap )
{
_capsule_list->loc[ n ].ptr = NULL;
}
else if( other != NULL )
{
// There should only be one capsule per capsule_metadata
assert( other->meta != meta );
}
}
// free+null all the non-static memory in the metadata struct // free+null all the non-static memory in the metadata struct
CLEAR( free_strv, meta->combined_exclude ); CLEAR( free_strv, meta->combined_exclude );
CLEAR( free_strv, meta->combined_export ); CLEAR( free_strv, meta->combined_export );
CLEAR( free_strv, meta->combined_nowrap ); CLEAR( free_strv, meta->combined_nowrap );
CLEAR( free , meta->active_prefix ); CLEAR( free , meta->active_prefix );
meta->handle = NULL;
CLEAR( ptr_list_free, cap->seen.all ); CLEAR( ptr_list_free, cap->seen.all );
CLEAR( ptr_list_free, cap->seen.some ); CLEAR( ptr_list_free, cap->seen.some );
CLEAR( free , meta->handle );
// flag it as closed just in case something tries to peek at it
meta->closed = 1;
// scrub all entries in the manifest pointing to this metadata
for( size_t n = 0; n < _capsule_metadata_list->next; n++ )
{
capsule_metadata *cm = ptr_list_nth_ptr( _capsule_metadata_list, n );
if( cm == meta )
_capsule_metadata_list->loc[ n ].ptr = NULL;
}
// poison the capsule struct and free it
memset( cap, 'X', sizeof(struct _capsule) );
free( cap );
} }
...@@ -15,6 +15,6 @@ struct _capsule ...@@ -15,6 +15,6 @@ struct _capsule
capsule_metadata *meta; capsule_metadata *meta;
}; };
extern ptr_list *_capsule_metadata_list; extern ptr_list *_capsule_list;
extern dlsymfunc capsule_dl_symbol; extern dlsymfunc capsule_dl_symbol;
extern dlopnfunc capsule_dl_open; extern dlopnfunc capsule_dl_open;
...@@ -51,12 +51,12 @@ capsule_external_dlsym (void *handle, const char *symbol) ...@@ -51,12 +51,12 @@ capsule_external_dlsym (void *handle, const char *symbol)
DEBUG( DEBUG_DLFUNC|DEBUG_WRAPPERS, "dlsym(%s)", symbol ); DEBUG( DEBUG_DLFUNC|DEBUG_WRAPPERS, "dlsym(%s)", symbol );
void *addr = NULL; void *addr = NULL;
for( size_t n = 0; n < _capsule_metadata_list->next; n++ ) for( size_t n = 0; n < _capsule_list->next; n++ )
{ {
capsule_metadata *m = ptr_list_nth_ptr( _capsule_metadata_list, n ); capsule cap = ptr_list_nth_ptr( _capsule_list, n );
// TODO: If handle != m->handle->dl_handle, should we skip it? // TODO: If handle != cap->dl_handle, should we skip it?
// TODO: RTLD_NEXT isn't implemented (is it implementable?) // TODO: RTLD_NEXT isn't implemented (is it implementable?)
addr = capsule_dl_symbol ( m->handle->dl_handle, symbol ); addr = capsule_dl_symbol ( cap->dl_handle, symbol );
if( addr ) if( addr )
{ {
...@@ -66,7 +66,7 @@ capsule_external_dlsym (void *handle, const char *symbol) ...@@ -66,7 +66,7 @@ capsule_external_dlsym (void *handle, const char *symbol)
// or if we are unable to determine where it came from (what?) // or if we are unable to determine where it came from (what?)
if( dladdr( addr, &dso ) ) if( dladdr( addr, &dso ) )
{ {
if( !dso_is_exported( dso.dli_fname, m->combined_export ) ) if( !dso_is_exported( dso.dli_fname, cap->meta->combined_export ) )
addr = NULL; addr = NULL;
DEBUG( DEBUG_DLFUNC|DEBUG_WRAPPERS, DEBUG( DEBUG_DLFUNC|DEBUG_WRAPPERS,
...@@ -127,28 +127,27 @@ capsule_external_dlopen(const char *file, int flag) ...@@ -127,28 +127,27 @@ capsule_external_dlopen(const char *file, int flag)
debug_flags |= DEBUG_RELOCS; debug_flags |= DEBUG_RELOCS;
// This may not even be necessary, so it should not be fatal. // 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: // We do want to log it though as it might be an important clue:
for( size_t n = 0; n < _capsule_metadata_list->next; n++ ) for( size_t n = 0; n < _capsule_list->next; n++ )
{ {
capsule_metadata *m = ptr_list_nth_ptr( _capsule_metadata_list, n ); const capsule c = ptr_list_nth_ptr( _capsule_list, n );
const capsule c = m->handle;
if( capsule_relocate( c, NULL, &error ) != 0 ) if( capsule_relocate( c, NULL, &error ) != 0 )
{ {
fprintf( stderr, fprintf( stderr,
"relocation from %s after dlopen(%s, …) failed: %s\n", "relocation from %s after dlopen(%s, …) failed: %s\n",
m->soname, file, error ); c->meta->soname, file, error );
free( error ); free( error );
} }
if( capsule_relocate_except( c, if( capsule_relocate_except( c,
m->dl_wrappers, c->meta->dl_wrappers,
(const char **)m->combined_nowrap, (const char **)c->meta->combined_nowrap,
&error ) != 0 ) &error ) != 0 )
{ {
fprintf( stderr, fprintf( stderr,
"dl-wrapper relocation from %s after " "dl-wrapper relocation from %s after "
"dlopen(%s, …) failed: %s\n", "dlopen(%s, …) failed: %s\n",
m->soname, file, error ); c->meta->soname, file, error );
free( error ); free( error );
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment