You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
SocketMbedTLS::close() calls mbedtls_psa_crypto_free(), tearing down process-global PSA state while other sockets use it (heap corruption) #612
With mbedTLS 3.6+ (and 4.x), SocketMbedTLS calls psa_crypto_init() in its constructor and mbedtls_psa_crypto_free() in close() (ixwebsocket/IXSocketMbedTLS.cpp, currently lines 55 and 332).
mbedtls_psa_crypto_free() is not a per-socket cleanup. It tears down mbedTLS's process-global PSA state: all key slots and the global entropy/RNG. In any process with more than one TLS connection alive, closing one socket wipes state that the others are still using. The symptoms are glibc heap-corruption aborts and segfaults in other threads.
Observed
A process with ~6 concurrent ix::WebSocket TLS connections, each reconnecting on its own thread, aborted repeatedly. Two representative backtraces from core dumps:
Minimal reproduction (deterministic, no server needed):
Construct socket A, then confirm PSA works (psa_generate_random succeeds).
Construct and close() socket B.
Call psa_generate_random again on behalf of socket A. It now returns PSA_ERROR_BAD_STATE (-137).
Suggested fix
Remove mbedtls_psa_crypto_free() from SocketMbedTLS::close(). PSA is process-wide, and freeing it belongs to process teardown (or to the application), not to any one socket. psa_crypto_init() is idempotent, so keeping it in the constructor is fine.
Related: initMBedTLS() runs from both the constructor and init(). With MBEDTLS_THREADING_C enabled, that re-initialises the entropy/ctr_drbg/ssl context mutexes without freeing them first. A per-socket "already initialised" guard avoids that.
Worth documenting: concurrent use of PSA from multiple threads also requires mbedTLS to be built with MBEDTLS_THREADING_C. The stock mbedtls_config.h leaves it off.
I can open a PR with the change and a small regression test if that's useful.
Argh. I think we need some global function to call to reclaim memory when terminating, like we have an init... function for windows.
And remove that function, thanks for catching this. Yes please make a PR if you'd like. Ideally we would flag the versions that were affected in the PR / commit / release note whatever.
Activity
bsergean commentedon Sep 30, 2026
Argh. I think we need some global function to call to reclaim memory when terminating, like we have an init... function for windows.
And remove that function, thanks for catching this. Yes please make a PR if you'd like. Ideally we would flag the versions that were affected in the PR / commit / release note whatever.
Thanks !