X-Git-Url: https://git.cworth.org/git?p=fips;a=blobdiff_plain;f=dlwrap.c;h=036d981d909feb56e857726b7a0ff0bf165d9763;hp=4bdb12c392ae6587cccd144d1996f306e96652a7;hb=HEAD;hpb=44b4f7ecdfb8c538aa7616d2ea718f7465446388 diff --git a/dlwrap.c b/dlwrap.c index 4bdb12c..036d981 100644 --- a/dlwrap.c +++ b/dlwrap.c @@ -23,21 +23,74 @@ #define _GNU_SOURCE #include -#include -#include +#include -#include +#include "fips.h" #include "dlwrap.h" -#define STRNCMP_LITERAL(var, literal) \ - strncmp ((var), (literal), sizeof (literal) - 1) +#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); +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 * +dlwrap_dlopen_libfips (void) +{ + Dl_info info; + + /* 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); + } + + return dlwrap_real_dlopen (info.dli_fname, RTLD_NOW); +} + /* 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 @@ -46,29 +99,44 @@ typedef void * (* fips_dlsym_t)(void *handle, const char *symbol); void * dlopen (const char *filename, int flag) { - Dl_info info; - - /* Not libGL, so just return real dlopen */ - if (STRNCMP_LITERAL (filename, "libGL.so")) - return dlwrap_real_dlopen (filename, flag); - - /* Redirect all dlopens to libGL to our own wrapper library. - * We find our own filename by looking up this very function - * (that is, this "dlopen"), with dladdr).*/ - if (dladdr (dlopen, &info)) { - libfips_handle = dlwrap_real_dlopen (info.dli_fname, flag); - return libfips_handle; - } else { - fprintf (stderr, "Error: Failed to redirect dlopen of %s:\n", - filename); - exit (1); - } + 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 * dlwrap_real_dlopen (const char *filename, int flag) { - fips_dlopen_t real_dlopen = NULL; + static fips_dlopen_t real_dlopen = NULL; if (! real_dlopen) { real_dlopen = (fips_dlopen_t) dlwrap_real_dlsym (RTLD_NEXT, "dlopen"); @@ -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,17 +174,23 @@ 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); } -extern void *__dlsym (void *handle, const char *name); void * dlwrap_real_dlsym (void *handle, const char *name) {