]> git.cworth.org Git - fips/commitdiff
fips: Fix dlsym wrapper for egl symbols
authorCarl Worth <cworth@cworth.org>
Tue, 2 Jul 2013 19:28:03 +0000 (12:28 -0700)
committerCarl Worth <cworth@cworth.org>
Wed, 3 Jul 2013 00:29:58 +0000 (17:29 -0700)
Previously, fips was failing to provide its own wrapped versions for
functions such as eglMakeCurrent if the application was using dlsym to
locate the symbol. This led to the failure of the egl-opengl-dlopen-*
tests in the test suite.

The root of the problem was that the fips wrapper for dlopen was only
returning the libfips_handle if dlopen was requested for
"libGL.so". But here, we need to also intercept a dlopen for
"libEGL.so" as well.

However, the fix is not as simple as updating dlopen.

Previously, if dlsym failed to find a libfips-specific version of the
symbol of interest it would defer unconditionally to a call to the
real dlsym with a handle dlopened from "libGL.so". That's obviously
the wrong thing for symbols sougth from "libEGL.so". So, now, our
dlopen caches the originally dlopen'ed handles and encodes an index
into its return value so that the final dlsym can reference the
correct handle in order to find its symbol.

This commit fixes the egl-opengl-dlopen-dlsym and
egl-opengl-dlopen-gpa test cases.

dlwrap.c
fips.h

index 69ffbd16fc6dde0dace5289aba1986f900ca5725..aff9e625eda298680cc890f88061ea1845d97e65 100644 (file)
--- a/dlwrap.c
+++ b/dlwrap.c
@@ -23,6 +23,8 @@
 #define _GNU_SOURCE
 #include <dlfcn.h>
 
+#include <assert.h>
+
 #include "fips.h"
 
 #include "dlwrap.h"
@@ -32,6 +34,35 @@ 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"
+};
+
+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;
+}
+
 /* 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
@@ -42,6 +73,7 @@ dlopen (const char *filename, int flag)
 {
        Dl_info info;
        void *ret;
+       unsigned index;
 
        /* Before deciding whether to redirect this dlopen to our own
         * library, we call the real dlopen. This assures that any
@@ -50,15 +82,19 @@ dlopen (const char *filename, int flag)
         * our own library, and not what is opened here. */
        ret = dlwrap_real_dlopen (filename, flag);
 
-       /* Not libGL, so just return real dlopen */
-       if (STRNCMP_LITERAL (filename, "libGL.so"))
+       /* If filename is not a wrapped library, just return real dlopen */
+       if (! find_wrapped_library_index (filename, &index))
                return ret;
 
-       /* Otherwise, for all libGL lookups we redirectl dlopens to
-        * our own library. If we've resolved libfips_handle before,
-        * our work is done. */
+       assert (index < ARRAY_SIZE(orig_handles));
+       orig_handles[index] = ret;
+
+       /* 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. */
        if (libfips_handle)
-               return libfips_handle;
+               return libfips_handle + index;
 
        /* We find our own filename by looking up this very function
         * (that is, this "dlopen"), with dladdr).*/
@@ -70,7 +106,7 @@ dlopen (const char *filename, int flag)
 
        libfips_handle = dlwrap_real_dlopen (info.dli_fname, flag);
 
-       return libfips_handle;
+       return libfips_handle + index;
 }
 
 void *
@@ -89,21 +125,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;
@@ -112,13 +150,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);
 }
 
diff --git a/fips.h b/fips.h
index 306ea1bf1405efa51efa745bf78361d6cfdcdfcd..20653ff68b013e8363223f92135724f03491d379 100644 (file)
--- a/fips.h
+++ b/fips.h
@@ -39,4 +39,6 @@
 #define STRNCMP_LITERAL(var, literal) \
     strncmp ((var), (literal), sizeof (literal) - 1)
 
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+
 #endif