Skip to content

Commit b1e34a2

Browse files
NormBliviuchircu
authored andcommitted
tls_openssl: fix per-thread state double-free across fork()
Register a pthread_atfork prepare handler that calls OPENSSL_thread_stop() before each fork(). CRYPTO_set_mem_functions() routes all OpenSSL allocations to shared memory, but per-thread structures (ERR_STATE, DRBG) use thread-local storage pointers inherited across fork(). Without cleanup, child processes inherit a stale pointer to the parent per-thread state; if the parent frees or re-creates that state, the child next OpenSSL call triggers a double-free (detected by QM_MALLOC_DBG as SIGABRT). After OPENSSL_thread_stop() the thread-local pointer is NULL. Both parent and child lazily allocate fresh per-thread state on the next OpenSSL call. This complements the existing on_exit(_exit) handler which covers the same class of double-free at process exit time. (cherry picked from commit c8d148c) (cherry picked from commit 66cca03)
1 parent 0b482b8 commit b1e34a2

1 file changed

Lines changed: 32 additions & 0 deletions

File tree

modules/tls_openssl/openssl.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <openssl/opensslv.h>
3030
#include <openssl/err.h>
3131
#include <openssl/rand.h>
32+
#include <pthread.h>
3233

3334
#include "../../dprint.h"
3435
#include "../../mem/shm_mem.h"
@@ -162,6 +163,30 @@ static void openssl_on_exit(int status, void *param)
162163
}
163164
#endif
164165

166+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
167+
/*
168+
* Clean up OpenSSL per-thread state (ERR_STATE, DRBG, etc.) in the parent
169+
* process before fork(). CRYPTO_set_mem_functions() routes all OpenSSL
170+
* allocations to shared memory, but per-thread structures use thread-local
171+
* storage pointers that are inherited across fork(). Without this cleanup,
172+
* child processes inherit a stale pointer to the parent's per-thread state
173+
* in shared memory; if the parent frees or re-creates that state, the
174+
* child's next OpenSSL call triggers a double-free (detected by
175+
* QM_MALLOC_DBG as SIGABRT).
176+
*
177+
* After OPENSSL_thread_stop(), the thread-local pointer is NULL. Both
178+
* parent and child lazily allocate fresh per-thread state on the next
179+
* OpenSSL call.
180+
*
181+
* This complements the on_exit(_exit) workaround above, which prevents the
182+
* same class of double-free at process *exit* time.
183+
*/
184+
static void openssl_pre_fork(void)
185+
{
186+
OPENSSL_thread_stop();
187+
}
188+
#endif
189+
165190
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
166191
static int check_for_krb(void)
167192
{
@@ -297,6 +322,13 @@ static int mod_init(void)
297322
on_exit(openssl_on_exit, NULL);
298323
#endif
299324

325+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
326+
if (pthread_atfork(openssl_pre_fork, NULL, NULL) != 0) {
327+
LM_ERR("failed to register atfork handler for OpenSSL cleanup\n");
328+
return -1;
329+
}
330+
#endif
331+
300332
return 0;
301333
}
302334

0 commit comments

Comments
 (0)