]> git.cworth.org Git - fips/blobdiff - dlwrap.c
Add explicit link to libpthread, to work around debugging issues
[fips] / dlwrap.c
index 4bdb12c392ae6587cccd144d1996f306e96652a7..036d981d909feb56e857726b7a0ff0bf165d9763 100644 (file)
--- a/dlwrap.c
+++ b/dlwrap.c
 #define _GNU_SOURCE
 #include <dlfcn.h>
 
-#include <stdio.h>
-#include <stdlib.h>
+#include <assert.h>
 
-#include <string.h>
+#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)
 {