summaryrefslogtreecommitdiff
path: root/dispatch
diff options
context:
space:
mode:
authorJosé Fonseca <jfonseca@vmware.com>2013-06-15 11:31:53 +0100
committerJosé Fonseca <jfonseca@vmware.com>2013-06-15 11:33:27 +0100
commit7700f74f294a28e57860487b917c8807156b3ad1 (patch)
treed8b0af0a4f5df9dd1eeddc8bb6ffc567523402df /dispatch
parent5785b4f8e6bebc89c85316253ab4f763065a0264 (diff)
Prevent infinite recursion with Steam's overlay.
Diffstat (limited to 'dispatch')
-rw-r--r--dispatch/glproc_gl.cpp73
1 files changed, 72 insertions, 1 deletions
diff --git a/dispatch/glproc_gl.cpp b/dispatch/glproc_gl.cpp
index 1f3e9fc9..2516dab8 100644
--- a/dispatch/glproc_gl.cpp
+++ b/dispatch/glproc_gl.cpp
@@ -145,6 +145,73 @@ _getPrivateProcAddress(const char *procName)
#else
+static inline void
+logSymbol(const char *name, void *ptr) {
+ if (0) {
+ if (ptr) {
+ Dl_info info;
+ if (ptr && dladdr(ptr, &info)) {
+ os::log("apitrace: %s -> \"%s\"\n", name, info.dli_fname);
+ }
+ } else {
+ os::log("apitrace: %s -> NULL\n", name);
+ }
+ }
+}
+
+
+#ifdef __GLIBC__
+extern "C" void * __libc_dlsym(void *, const char *);
+#endif
+
+
+/*
+ * Protect against dlsym interception.
+ *
+ * We implement the whole API, so we don't need to intercept dlsym -- dlopen is
+ * enough. However we need to protect against other dynamic libraries
+ * intercepting dlsym, to prevent infinite recursion,
+ *
+ * In particular the Steam Community Overlay advertises dlsym. See also
+ * http://lists.freedesktop.org/archives/apitrace/2013-March/000573.html
+ */
+static inline void *
+_dlsym(void *handle, const char *symbol)
+{
+ void *result;
+
+#ifdef __GLIBC__
+ /*
+ * We rely on glibc's internal __libc_dlsym. See also
+ * http://www.linuxforu.com/2011/08/lets-hook-a-library-function/
+ *
+ * Use use it to obtain the true dlsym. We don't use __libc_dlsym directly
+ * because it does not support things such as RTLD_NEXT.
+ */
+ typedef void * (*PFN_DLSYM)(void *, const char *);
+ static PFN_DLSYM dlsym_ptr = NULL;
+ if (!dlsym_ptr) {
+ void *libdl_handle = _dlopen("libdl.so.2", RTLD_LOCAL | RTLD_NOW);
+ if (libdl_handle) {
+ dlsym_ptr = (PFN_DLSYM)__libc_dlsym(libdl_handle, "dlsym");
+ }
+ if (!dlsym_ptr) {
+ os::log("apitrace: error: failed to look up real dlsym\n");
+ return NULL;
+ }
+
+ logSymbol("dlsym", (void*)dlsym_ptr);
+ }
+
+ result = dlsym_ptr(handle, symbol);
+#else
+ result = dlsym(handle, symbol);
+#endif
+
+ return result;
+}
+
+
/*
* Lookup a libGL symbol
*/
@@ -188,7 +255,11 @@ void * _libgl_sym(const char *symbol)
}
}
- return dlsym(_libGlHandle, symbol);
+ result = _dlsym(_libGlHandle, symbol);
+
+ logSymbol(symbol, result);
+
+ return result;
}