]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Add a tor_tls_release_socket() function.
authorNick Mathewson <nickm@torproject.org>
Wed, 12 Sep 2018 15:02:59 +0000 (11:02 -0400)
committerNick Mathewson <nickm@torproject.org>
Wed, 12 Sep 2018 15:12:05 +0000 (11:12 -0400)
This function tells the underlying TLS object that it shouldn't
close the fd on exit.  Mostly, we hope not to have to use it, since
the NSS implementation is kludgey, but it should allow us to fix

src/lib/tls/tortls.h
src/lib/tls/tortls_nss.c
src/lib/tls/tortls_openssl.c

index 459192708178b6ab64208ed8effa1eb2a3c37406..3f1098bbacc69f0c160317ce2dd99b9304cb7c02 100644 (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);
index 53adfedf322be861c91a2574499a2e8d0513fd76..1b2032764de85b67c59225309b33a73da087f4a1 100644 (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)
 {
index dc6c0bee9cdb28982ad6d6c275a42898509d944c..534a90de5dec755207e771fdb4c80e21eb9e7adf 100644 (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)
 {