diff --git a/capsule/capsule-dlmopen.c b/capsule/capsule-dlmopen.c index eff7877a59eb54d3942921f1458e1744bb43d348..9c20f7847390d3581edf0c581296e4720a120e8b 100644 --- a/capsule/capsule-dlmopen.c +++ b/capsule/capsule-dlmopen.c @@ -419,3 +419,38 @@ cleanup: ld_libs_finish( &ldlibs ); return res; } + +static int +dso_is_exported (const char *dsopath, const char **exported) +{ + for( const char **ex = exported; ex && *ex; ex++ ) + if( soname_matches_path( *ex, dsopath ) ) + return 1; + + return 0; +} + +void * +capsule_shim_dlsym (void *capsule, + void *handle, + const char *symbol, + const char **exported) +{ + void *addr = NULL; + + if( (addr = dlsym( capsule, symbol )) ) + { + 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, exported ) ) + addr = NULL; + } + + if( addr == NULL ) + addr = dlsym( handle, symbol ); + + return addr; +} diff --git a/capsule/capsule.h b/capsule/capsule.h index 3fbe0202f1d018de59847fedd7551d7d84f78ffd..0de488575fe1987048ffa35eadce25cb8cfbba08 100644 --- a/capsule/capsule.h +++ b/capsule/capsule.h @@ -170,3 +170,37 @@ void *capsule_shim_dlopen(Lmid_t ns, const char **exclude, const char *file, int flag); + +/** + * capsule_shim_dlsym: + * @capsule: A dl handle as returned by capsule_dlmopen() + * @handle: A dl handle, as passed to dlsym() + * @symbol: A symbol name, as passed to dlsym() + * @exported: An array of DSO names considered to ba valid symbol sources + * + * Returns: a void * symbol address (cf dlsym()) + * + * Some libraries have a use pattern in which their caller/user + * uses dlsym() to obtain symbols rather than using those symbols + * directly in its own code (libGL is an example of this). + * + * Since the target library may have a different symbol set than the + * one the libcapsule proxy shim was generated from we can't rely on + * dlsym() finding those symbols in the shim's symbol table. + * + * 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. + * + * This function provides the functionality described above, and is + * intended for use in a suitable wrapper implemented in the the shim + * library. + */ +void * +capsule_shim_dlsym (void *capsule, + void *handle, + const char *symbol, + const char **exported); diff --git a/documentation.mk b/documentation.mk index ef3e21c4301f02c4a0cdde082ab114a05931f3cc..9d3ab5b8fcf7b1237abda9fc1847b7f280016643 100644 --- a/documentation.mk +++ b/documentation.mk @@ -29,5 +29,6 @@ man_MANS += capsule_dlmopen.3 man_MANS += capsule_init.3 man_MANS += capsule_relocate.3 man_MANS += capsule_shim_dlopen.3 +man_MANS += capsule_shim_dlsym.3 CLEANFILES += $(man_MANS) diff --git a/utils/utils.c b/utils/utils.c index a31422421aae44005af3175c4a7562f832e21644..2d57a1415371daf39fd9c103f894097da756342d 100644 --- a/utils/utils.c +++ b/utils/utils.c @@ -131,3 +131,21 @@ void set_debug_flags (const char *control) (debug_flags & DEBUG_RELOCS ) ? 'Y' : 'n' , (debug_flags & DEBUG_ELF ) ? 'Y' : 'n' ); } + +// soname: bare libfoo.so.X style name +// path: [possibly absolute] path to DSO +// return true if soname: libFOO.so.X matches +// path: /path/to/libFOO.so.X.Y or /path/to/libFOO.so.X +int soname_matches_path (const char *soname, const char *path) +{ + const char *path_soname = strrchr( path, '/' ); + const char *pattern = path_soname ? path_soname + 1: path; + const size_t slen = strlen( soname ); + + if( strncmp( soname, pattern, slen ) != 0 ) + return 0; + + const char *end = pattern + slen; + + return ( *end == '\0' || *end == '.' ); +} diff --git a/utils/utils.h b/utils/utils.h index 035a2260117934df9a3049b70bd8c4c1c7b97b23..87cba968b5905bf5dc363c53f0686f81a487dae1 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -40,3 +40,4 @@ char *safe_strncpy (char *dest, const char *src, size_t n); int resolve_link (const char *prefix, char *path, char *dir); +int soname_matches_path (const char *soname, const char *path);