diff --git a/src/hush/tlsmanager.cpp b/src/hush/tlsmanager.cpp index 4b65e215f..4b6093487 100644 --- a/src/hush/tlsmanager.cpp +++ b/src/hush/tlsmanager.cpp @@ -593,6 +593,7 @@ int TLSManager::threadSocketHandler(CNode* pnode, fd_set& fdsetRecv, fd_set& fds int64_t nPassBytes = 0; bool fKeepReading = true; while (fKeepReading) { + int nSSLPending = 0; if (nRecvBase + nPassBytes > (int64_t)ReceiveFloodSize()) break; { @@ -609,6 +610,10 @@ int TLSManager::threadSocketHandler(CNode* pnode, fd_set& fdsetRecv, fd_set& fds wolfSSL_ERR_clear_error(); // clear the error queue, otherwise we may be reading an old error that occurred previously in the current thread nBytes = wolfSSL_read(pnode->ssl, pchBuf, sizeof(pchBuf)); nRet = wolfSSL_get_error(pnode->ssl, nBytes); + // Capture TLS buffered-byte count while still under cs_hSocket; the drain-continuation + // check below runs unlocked, so touching pnode->ssl there would race with + // SocketSendData / CloseSocketDisconnect (which free ssl) -> data race / use-after-free. + nSSLPending = wolfSSL_pending(pnode->ssl); } else { nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT); nRet = WSAGetLastError(); @@ -628,7 +633,7 @@ int TLSManager::threadSocketHandler(CNode* pnode, fd_set& fdsetRecv, fd_set& fds // buffer, or TLS has buffered decrypted bytes) and within the per-pass cap. // The flood ceiling is enforced pre-read at the top of the loop. if (fKeepReading) { - bool fMore = (nBytes == (int)sizeof(pchBuf)) || (bIsSSL && wolfSSL_pending(pnode->ssl) > 0); + bool fMore = (nBytes == (int)sizeof(pchBuf)) || (bIsSSL && nSSLPending > 0); if (!fMore || ++nDrainReads >= MAX_DRAIN_READS) fKeepReading = false; }