openssl: fix fd double-close in relpTcpDestruct#292
Conversation
There was a problem hiding this comment.
Code Review
This pull request modifies src/tcp.c to call relpTcpDestructTLS earlier in relpTcpDestruct and changes the OpenSSL socket BIO creation to use BIO_NOCLOSE instead of BIO_CLOSE. Feedback highlights a potential double-free vulnerability in relpTcpConnectTLSInit_ossl on error paths where BIO_free is manually called after ownership of the BIO has already been transferred to the SSL structure.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
1 issue found across 1 file
Confidence score: 2/5
- In
src/tcp.caround theSSL_set_bio(pThis->ssl, conn, conn)call, BIO ownership appears to be mishandled (the SSL object takes ownership, with only one reference consumed when the same BIO is used twice), which can lead to a double-free/use-after-free or leak during connection teardown; adjust the post-call lifetime management to match OpenSSL ownership rules before merging.
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
relpTcpDestruct() closed the socket fd before calling relpTcpDestructTLS(), causing SSL_shutdown() to operate on an already-closed fd. Additionally, BIO_new_socket() was called with BIO_CLOSE, making SSL_free() close the fd a second time via the BIO destructor. Strace on every TLS teardown: shutdown(12, SHUT_RDWR) = 0 close(12) = 0 # relpTcpDestruct write(12, ...) = -1 EBADF # SSL_shutdown on closed fd close(12) = -1 EBADF # SSL_free BIO_CLOSE Fix: - Move relpTcpDestructTLS() before the socket close so SSL_shutdown() can send the close_notify on a valid fd. - Change BIO_new_socket() from BIO_CLOSE to BIO_NOCLOSE so SSL_free() does not close the fd.
|
The coverage / test error is something wrong on CI side. |
I agree |
|
@rgerhards Is there something wrong with my PR? |
relpTcpDestruct()closed the socket fd before callingrelpTcpDestructTLS(), causingSSL_shutdown()to operate on an already-closed fd. Additionally,BIO_new_socket()was called withBIO_CLOSE, makingSSL_free()close the fd a second time via the BIO destructor. Strace on every TLS teardown:Fix:
relpTcpDestructTLS()before the socket close soSSL_shutdown()can send the close_notify on a valid fd.BIO_new_socket()fromBIO_CLOSEtoBIO_NOCLOSEsoSSL_free()does not close the fd.Summary by cubic
Fixes EBADF errors and fd double-close in TLS teardown by destroying TLS before closing the socket and ensuring OpenSSL doesn’t close or free the socket/BIO.
relpTcpDestructTLS()beforeshutdown/closesoSSL_shutdown()runs on a valid fd and sendsclose_notify.BIO_NOCLOSEand transfer ownership to SSL (SSL_set_bio(...); conn = NULL) soSSL_free()doesn’t close or double-free the socket/BIO.Written for commit 940cd18. Summary will update on new commits.