Bug 18192 - dlerror not thread-safe when libpthread loaded through dlopen
Summary: dlerror not thread-safe when libpthread loaded through dlopen
Status: NEW
Alias: None
Product: glibc
Classification: Unclassified
Component: dynamic-link (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Depends on:
Reported: 2015-04-01 21:42 UTC by William Ahern
Modified: 2018-10-09 09:03 UTC (History)
3 users (show)

See Also:
Last reconfirmed:
fweimer: security-

Tickle dlerror from multiple threads (1.21 KB, text/plain)
2015-04-01 21:42 UTC, William Ahern

Note You need to log in before you can comment on or make changes to this bug.
Description William Ahern 2015-04-01 21:42:32 UTC
Created attachment 8223 [details]
Tickle dlerror from multiple threads

__dlerror and _dlerror_run in dlfcn.h will use a shared, static buffer if pthreads is not present when initializing internal state. And they continue using the shared buffer even after pthreads is loaded. This can result in double frees, NULL pointer dereferences, and other fun.

I ran into this bug via a Lua module. No Lua interpreter shipped on a major distribution links the interpreter against libpthread.so. However, there are many Lua modules which use pthreads and cause libpthread to be linked in via dlopen. If dlopen/dlclose are used from multiple threads (e.g. spinning up new Lua VMs in the threads, which will then load modules), then you can trigger this bug. You're much more likely to encounter problems if the threads are short-lived and the Lua interpreters unload their modules via dlclose, or if they try to load non-existent modules.

Attached is a simple proof of concept in plain C. It loads libpthread using dlopen("libpthread.so.0", RTLD_GLOBAL), spins up multiple threads, and from each thread tickles dlerror by repeatedly attempting to open non-existent libraries.

Note that Lua modules are usually loaded RTLD_LOCAL, so that might complicate any solution.

FWIW, strsignal.c has this same problem. where_is_shmfs in shm_open.c also has an initialization race. gaiconf_init in getaddrinfo.c might be subject to a race, but I couldn't quickly determine which globals it accesses.