Merge branch 'nss_27451'

This commit is contained in:
Nick Mathewson 2018-09-14 10:22:38 -04:00
commit e43ae24e7d
4 changed files with 74 additions and 3 deletions

View File

@ -638,8 +638,19 @@ connection_free_minimal(connection_t *conn)
if (connection_speaks_cells(conn)) {
or_connection_t *or_conn = TO_OR_CONN(conn);
tor_tls_free(or_conn->tls);
or_conn->tls = NULL;
if (or_conn->tls) {
if (! SOCKET_OK(conn->s)) {
/* The socket has been closed by somebody else; we must tell the
* TLS object not to close it. */
tor_tls_release_socket(or_conn->tls);
} else {
/* The tor_tls_free() call below will close the socket; we must tell
* the code below not to close it a second time. */
conn->s = TOR_INVALID_SOCKET;
}
tor_tls_free(or_conn->tls);
or_conn->tls = NULL;
}
or_handshake_state_free(or_conn->handshake_state);
or_conn->handshake_state = NULL;
tor_free(or_conn->nickname);

View File

@ -94,6 +94,7 @@ void tor_tls_set_renegotiate_callback(tor_tls_t *tls,
void (*cb)(tor_tls_t *, void *arg),
void *arg);
int tor_tls_is_server(tor_tls_t *tls);
void tor_tls_release_socket(tor_tls_t *tls);
void tor_tls_free_(tor_tls_t *tls);
#define tor_tls_free(tls) FREE_AND_NULL(tor_tls_t, tor_tls_free_, (tls))
int tor_tls_peer_has_cert(tor_tls_t *tls);

View File

@ -414,6 +414,43 @@ tor_tls_set_renegotiate_callback(tor_tls_t *tls,
/* We don't support renegotiation-based TLS with NSS. */
}
/**
* Tell the TLS library that the underlying socket for <b>tls</b> has been
* closed, and the library should not attempt to free that socket itself.
*/
void
tor_tls_release_socket(tor_tls_t *tls)
{
if (! tls)
return;
/* NSS doesn't have the equivalent of BIO_NO_CLOSE. If you replace the
* fd with something that's invalid, it causes a memory leak in PR_Close.
*
* If there were a way to put the PRFileDesc into the CLOSED state, that
* would prevent it from closing its fd -- but there doesn't seem to be a
* supported way to do that either.
*
* So instead: we make a new sacrificial socket, and replace the original
* socket with that one. This seems to be the best we can do, until we
* redesign the mainloop code enough to make this function unnecessary.
*/
tor_socket_t sock =
tor_open_socket_nonblocking(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (!sock) {
log_warn(LD_NET, "Out of sockets when trying to shut down an NSS "
"connection");
return;
}
PRFileDesc *tcp = PR_GetIdentitiesLayer(tls->ssl, PR_NSPR_IO_LAYER);
if (BUG(! tcp)) {
return;
}
PR_ChangeFileDescNativeHandle(tcp, sock);
}
void
tor_tls_impl_free_(tor_tls_impl_t *tls)
{

View File

@ -1048,7 +1048,7 @@ tor_tls_new(tor_socket_t sock, int isServer)
goto err;
}
result->socket = sock;
bio = BIO_new_socket(sock, BIO_NOCLOSE);
bio = BIO_new_socket(sock, BIO_CLOSE);
if (! bio) {
tls_log_errors(NULL, LOG_WARN, LD_NET, "opening BIO");
#ifdef SSL_set_tlsext_host_name
@ -1154,6 +1154,28 @@ tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls)
#endif /* defined(SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) && ... */
}
/**
* Tell the TLS library that the underlying socket for <b>tls</b> has been
* closed, and the library should not attempt to free that socket itself.
*/
void
tor_tls_release_socket(tor_tls_t *tls)
{
if (! tls)
return;
BIO *rbio, *wbio;
rbio = SSL_get_rbio(tls->ssl);
wbio = SSL_get_wbio(tls->ssl);
if (rbio) {
BIO_set_close(rbio, BIO_NOCLOSE);
}
if (wbio && wbio != rbio) {
BIO_set_close(wbio, BIO_NOCLOSE);
}
}
void
tor_tls_impl_free_(tor_tls_impl_t *ssl)
{