diff options
author | José Fonseca <jfonseca@vmware.com> | 2013-06-15 11:31:53 +0100 |
---|---|---|
committer | José Fonseca <jfonseca@vmware.com> | 2013-06-15 11:33:27 +0100 |
commit | 7700f74f294a28e57860487b917c8807156b3ad1 (patch) | |
tree | d8b0af0a4f5df9dd1eeddc8bb6ffc567523402df /dispatch | |
parent | 5785b4f8e6bebc89c85316253ab4f763065a0264 (diff) |
Prevent infinite recursion with Steam's overlay.
Diffstat (limited to 'dispatch')
-rw-r--r-- | dispatch/glproc_gl.cpp | 73 |
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; } |