1 /* Copyright © 2013, Intel Corporation
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 /* dladdr is a glibc extension */
33 #define STRNCMP_LITERAL(var, literal) \
34 strncmp ((var), (literal), sizeof (literal) - 1)
38 typedef void * (* fips_dlopen_t)(const char * filename, int flag);
39 typedef void * (* fips_dlsym_t)(void *handle, const char *symbol);
41 /* Many (most?) OpenGL programs dlopen libGL.so.1 rather than linking
42 * against it directly, which means they would not be seeing our
43 * wrapped GL symbols via LD_PRELOAD. So we catch the dlopen in a
44 * wrapper here and redirect it to our library.
47 dlopen (const char *filename, int flag)
51 /* Not libGL, so just return real dlopen */
52 if (STRNCMP_LITERAL (filename, "libGL.so"))
53 return dlwrap_real_dlopen (filename, flag);
55 /* Redirect all dlopens to libGL to our own wrapper library.
56 * We find our own filename by looking up this very function
57 * (that is, this "dlopen"), with dladdr).*/
58 if (dladdr (dlopen, &info)) {
59 libfips_handle = dlwrap_real_dlopen (info.dli_fname, flag);
60 return libfips_handle;
62 fprintf (stderr, "Error: Failed to redirect dlopen of %s:\n",
69 dlwrap_real_dlopen (const char *filename, int flag)
71 fips_dlopen_t real_dlopen = NULL;
74 real_dlopen = (fips_dlopen_t) dlwrap_real_dlsym (RTLD_NEXT, "dlopen");
76 fprintf (stderr, "Error: Failed to find symbol for dlopen.\n");
81 return real_dlopen (filename, flag);
84 /* Since we redirect a dlopen of libGL.so to libfips we need to ensure
85 * that dlysm succeeds for all functions that might be defined in the
86 * real, underlying libGL library. But we're far too lazy to implement
87 * wrappers for function that would simply pass-through, so instead we
88 * also wrap dlysm and arrange for it to pass things through with
89 * RTLD_next if libfips does not have the function desired.
92 dlsym (void *handle, const char *name)
94 static void *libgl_handle = NULL;
97 /* All gl symbols are preferentially looked up in libfips. */
98 if (STRNCMP_LITERAL (name, "gl") == 0) {
99 symbol = dlwrap_real_dlsym (libfips_handle, name);
104 /* Failing that, anything specifically requested from the
105 * libfips library should be redirected to a real GL
107 if (handle == libfips_handle) {
109 libgl_handle = dlwrap_real_dlopen ("libGL.so.1", RTLD_LAZY);
110 return dlwrap_real_dlsym (libgl_handle, name);
113 /* And anything else is some unrelated dlsym. Just pass it through. */
114 return dlwrap_real_dlsym (handle, name);
117 extern void *__dlsym (void *handle, const char *name);
119 dlwrap_real_dlsym (void *handle, const char *name)
121 static fips_dlsym_t real_dlsym = NULL;
124 /* FIXME: This brute-force, hard-coded searching for a versioned
125 * symbol is really ugly. The only reason I'm doing this is because
126 * I need some way to lookup the "dlsym" function in libdl, but
127 * I can't use 'dlsym' to do it. So dlvsym works, but forces me
128 * to guess what the right version is.
130 * Potential fixes here:
132 * 1. Use libelf to actually inspect libdl.so and
133 * find the right version, (finding the right
134 * libdl.so can be made easier with
137 * 2. Use libelf to find the offset of the 'dlsym'
138 * symbol within libdl.so, (and then add this to
139 * the base address at which libdl.so is loaded
140 * as reported by dl_iterate_phdr).
142 * In the meantime, I'll just keep augmenting this
143 * hard-coded version list as people report bugs. */
144 const char *version[] = {
148 int num_versions = sizeof(version) / sizeof(version[0]);
150 for (i = 0; i < num_versions; i++) {
151 real_dlsym = (fips_dlsym_t) dlvsym (RTLD_NEXT, "dlsym",
156 if (i == num_versions) {
157 fprintf (stderr, "Internal error: Failed to find real dlsym\n");
159 "This may be a simple matter of fips not knowing about the version of GLIBC that\n"
160 "your program is using. Current known versions are:\n\n\t");
161 for (i = 0; i < num_versions; i++)
162 fprintf (stderr, "%s ", version[i]);
164 "\n\nYou can inspect your version by first finding libdl.so.2:\n"
166 "\tldd <your-program> | grep libdl.so\n"
168 "And then inspecting the version attached to the dlsym symbol:\n"
170 "\treadelf -s /path/to/libdl.so.2 | grep dlsym\n"
172 "And finally, adding the version to dlwrap.c:dlwrap_real_dlsym.\n");
178 return real_dlsym (handle, name);