Bug 21032 - pthread_key_create() destructors and segfault after a DSO unloading
Summary: pthread_key_create() destructors and segfault after a DSO unloading
Status: RESOLVED NOTABUG
Alias: None
Product: glibc
Classification: Unclassified
Component: nptl (show other bugs)
Version: 2.24
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-01-07 20:14 UTC by account disabled by myself since useless
Modified: 2023-02-08 12:07 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments
Minimal reproduction (866 bytes, application/zip)
2021-02-20 22:33 UTC, Aaron Hill
Details

Note You need to log in before you can comment on or make changes to this bug.
Description account disabled by myself since useless 2017-01-07 20:14:33 UTC
The pthread_key_create() and __nptl_deallocate_tsd() do not track the references to destructor's DSO like the __cxa_thread_atexit_impl().

Therefore the DSO, which holds a destructor's code, could be unloaded before destructor execution or before deleting a corresponding key.

So in a complex environment there is no way to know whether it is safe to unload a particular DSO or some tls-destructors are still left.

Suggest this should be fixed or documented, e.g. that the pthread_create_key() with a destructor should not be used from lib.so.
Comment 1 account disabled by myself since useless 2018-03-28 12:16:25 UTC
Related to bugs 18136, 21031.
Comment 2 Aaron Hill 2021-02-20 22:33:52 UTC
Created attachment 13236 [details]
Minimal reproduction

I've attached a minimal reproduction of the issue (GitHub repository: https://github.com/Aaron1011/pthread_dlopen)

It does the following:
1. Spawn a new thread from `main()`, and block on it using `pthread_join`
2. From the new thread, load a simple shared library, and call a function in it.
3. In the shared library, call `pthread_key_create` with a destrutor function, and call `pthread_setspecific` with a non-NULL value to force the destrutor to actually run on thread exit.
4. Back in the main program (on the thread), call `dlclose` on the shared library.
5. Return from the thread function

This causes the following segfault:

```
[Current thread is 1 (Thread 0x7facc3ff4640 (LWP 701108))]
gef➤  bt
#0  0x00007facc4229129 in ?? ()
#1  0x00007facc41cd411 in __nptl_deallocate_tsd.part.0 () from /usr/lib/libpthread.so.0
#2  0x00007facc41ce2ba in start_thread () from /usr/lib/libpthread.so.0
#3  0x00007facc40f7053 in clone () from /usr/lib/libc.so.6
gef➤  q
```
Comment 3 account disabled by myself since useless 2023-02-08 12:07:03 UTC
Not a bug for glibc, but the feature )