X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=dlwrap.c;h=036d981d909feb56e857726b7a0ff0bf165d9763;hb=47739542f4ffba033bb70a8f58d1a056889f717e;hp=9f623da549b3e74c2db2a261caddbe95e9e00081;hpb=54157251d30d586e8f97fb594f22bf18e9ac4bbe;p=fips diff --git a/dlwrap.c b/dlwrap.c index 9f623da..036d981 100644 --- a/dlwrap.c +++ b/dlwrap.c @@ -23,46 +23,114 @@ #define _GNU_SOURCE #include +#include + #include "fips.h" #include "dlwrap.h" +#include "glwrap.h" + void *libfips_handle; typedef void * (* fips_dlopen_t)(const char * filename, int flag); typedef void * (* fips_dlsym_t)(void *handle, const char *symbol); -/* Many (most?) OpenGL programs dlopen libGL.so.1 rather than linking - * against it directly, which means they would not be seeing our - * wrapped GL symbols via LD_PRELOAD. So we catch the dlopen in a - * wrapper here and redirect it to our library. - */ +static const char *wrapped_libs[] = { + "libGL.so", + "libEGL.so", + "libGLESv2.so" +}; + +static void *orig_handles[ARRAY_SIZE(wrapped_libs)]; + +/* Match 'filename' against an internal list of libraries for which + * libfips has wrappers. + * + * Returns true and sets *index_ret if a match is found. + * Returns false if no match is found. */ +static bool +find_wrapped_library_index (const char *filename, unsigned *index_ret) +{ + unsigned i; + + for (i = 0; i < ARRAY_SIZE(wrapped_libs); i++) { + if (strncmp(wrapped_libs[i], filename, + strlen (wrapped_libs[i])) == 0) + { + *index_ret = i; + return true; + } + } + + return false; +} + +/* Perform a dlopen on the libfips library itself. + * + * Many places in fips need to lookup symbols within the libfips + * library itself, (and not in any other library). This function + * provides a reliable way to get a handle for performing such + * lookups. + * + * The returned handle can be passed to dlwrap_real_dlsym for the + * lookups. */ void * -dlopen (const char *filename, int flag) +dlwrap_dlopen_libfips (void) { Dl_info info; - /* Not libGL, so just return real dlopen */ - if (STRNCMP_LITERAL (filename, "libGL.so")) - return dlwrap_real_dlopen (filename, flag); - - /* Otherwise, for all libGL lookups we redirectl dlopens to - * our own library. If we've resolved libfips_handle before, - * our work is done. */ - if (libfips_handle) - return libfips_handle; - - /* We find our own filename by looking up this very function - * (that is, this "dlopen"), with dladdr).*/ - if (dladdr (dlopen, &info) == 0) { - fprintf (stderr, "Error: Failed to redirect dlopen of %s:\n", - filename); + /* We first find our own filename by looking up a function + * known to exist only in libfips. This function itself + * (dlwrap_dlopen_libfips) is a good one for that purpose. */ + if (dladdr (dlwrap_dlopen_libfips, &info) == 0) { + fprintf (stderr, "Internal error: Failed to lookup filename of libfips library with dladdr\n"); exit (1); } - libfips_handle = dlwrap_real_dlopen (info.dli_fname, flag); + return dlwrap_real_dlopen (info.dli_fname, RTLD_NOW); +} - return libfips_handle; +/* Many (most?) OpenGL programs dlopen libGL.so.1 rather than linking + * against it directly, which means they would not be seeing our + * wrapped GL symbols via LD_PRELOAD. So we catch the dlopen in a + * wrapper here and redirect it to our library. + */ +void * +dlopen (const char *filename, int flag) +{ + void *ret; + unsigned index; + + /* Before deciding whether to redirect this dlopen to our own + * library, we call the real dlopen. This assures that any + * expected side-effects from loading the intended library are + * resolved. Below, we may still return a handle pointing to + * our own library, and not what is opened here. */ + ret = dlwrap_real_dlopen (filename, flag); + + /* If filename is not a wrapped library, just return real dlopen */ + if (! find_wrapped_library_index (filename, &index)) + return ret; + + /* When the application dlopens any wrapped library starting + * with 'libGL', (whether libGL.so.1 or libGLESv2.so.2), let's + * continue to use that library handle for future lookups of + * OpenGL functions. */ + if (STRNCMP_LITERAL (filename, "libGL") == 0) + glwrap_set_gl_handle (ret); + + assert (index < ARRAY_SIZE(orig_handles)); + orig_handles[index] = ret; + + if (libfips_handle == NULL) + libfips_handle = dlwrap_dlopen_libfips (); + + /* Otherwise, we return our own handle so that we can intercept + * future calls to dlsym. We encode the index in the return value + * so that we can later map back to the originally requested + * dlopen-handle if necessary. */ + return libfips_handle + index; } void * @@ -81,21 +149,23 @@ dlwrap_real_dlopen (const char *filename, int flag) return real_dlopen (filename, flag); } -/* Since we redirect a dlopen of libGL.so to libfips we need to ensure - * that dlysm succeeds for all functions that might be defined in the - * real, underlying libGL library. But we're far too lazy to implement - * wrappers for function that would simply pass-through, so instead we - * also wrap dlysm and arrange for it to pass things through with - * RTLD_next if libfips does not have the function desired. -*/ +/* Since we redirect dlopens of libGL.so and libEGL.so to libfips we + * need to ensure that dlysm succeeds for all functions that might be + * defined in the real, underlying libGL library. But we're far too + * lazy to implement wrappers for function that would simply + * pass-through, so instead we also wrap dlysm and arrange for it to + * pass things through with RTLD_next if libfips does not have the + * function desired. */ void * dlsym (void *handle, const char *name) { - static void *libgl_handle = NULL; static void *symbol; + unsigned index; - /* All gl symbols are preferentially looked up in libfips. */ - if (STRNCMP_LITERAL (name, "gl") == 0) { + /* All gl* and egl* symbols are preferentially looked up in libfips. */ + if (STRNCMP_LITERAL (name, "gl") == 0 || + STRNCMP_LITERAL (name, "egl") == 0) + { symbol = dlwrap_real_dlsym (libfips_handle, name); if (symbol) return symbol; @@ -104,13 +174,20 @@ dlsym (void *handle, const char *name) /* Failing that, anything specifically requested from the * libfips library should be redirected to a real GL * library. */ - if (handle == libfips_handle) { - if (! libgl_handle) - libgl_handle = dlwrap_real_dlopen ("libGL.so.1", RTLD_LAZY); - return dlwrap_real_dlsym (libgl_handle, name); + + /* We subtract the index back out of the handle (see the addition + * of the index in our wrapper for dlopen above) to then use the + * correct, original dlopen'ed handle for the library of + * interest. */ + index = handle - libfips_handle; + if (index < ARRAY_SIZE(orig_handles)) { + return dlwrap_real_dlsym (orig_handles[index], name); } - /* And anything else is some unrelated dlsym. Just pass it through. */ + /* And anything else is some unrelated dlsym. Just pass it + * through. (This also covers the cases of lookups with + * special handles such as RTLD_DEFAULT or RTLD_NEXT.) + */ return dlwrap_real_dlsym (handle, name); }