]> git.meshlink.io Git - meshlink/commitdiff
Fix potential incorrect destruction of channels.
authorGuus Sliepen <guus@meshlink.io>
Tue, 4 May 2021 19:51:50 +0000 (21:51 +0200)
committerGuus Sliepen <guus@meshlink.io>
Tue, 4 May 2021 19:54:57 +0000 (21:54 +0200)
utcp_abort_all_connections() was called when a node is blacklisted or a
a node reconnects with a different session ID. In both cases, all active
channels should be closed. However, utcp_abort_all_connections() also freed
the UTCP connection object, which would cause a double free when the
application freed the corresponding meshlink_channel object.

Rename utcp_abort_all_connections() to utcp_reset_all_connections(), and
have it not invalidate any handles.

src/graph.c
src/meshlink.c
src/utcp.c
src/utcp.h

index c7401b6a6341e669f0dfc7c5535d74a15fc54de5..9a2bfb191e77beb068ceb52477680761da96c94e 100644 (file)
@@ -150,7 +150,7 @@ static void check_reachability(meshlink_handle_t *mesh) {
                        n->session_id = n->prevedge->reverse->session_id;
 
                        if(n->utcp) {
-                               utcp_abort_all_connections(n->utcp);
+                               utcp_reset_all_connections(n->utcp);
                        }
 
                        n->status.validkey = false;
index 5d5733e7bf432e26d7d1923c510c39edd6a41a9b..fe11af2cc44966a309afea3e224ca9935d2b2229 100644 (file)
@@ -3517,7 +3517,7 @@ static bool blacklist(meshlink_handle_t *mesh, node_t *n) {
                }
        }
 
-       utcp_abort_all_connections(n->utcp);
+       utcp_reset_all_connections(n->utcp);
 
        n->mtu = 0;
        n->minmtu = 0;
index fa45e9c625b4b4e1d28c07ea49d881dad40e2107..ca91bee26ef6d21c0f0f57dd743c27c0f9b14f8b 100644 (file)
@@ -2077,9 +2077,6 @@ static bool reset_connection(struct utcp_connection *c) {
        buffer_clear(&c->sndbuf);
        buffer_clear(&c->rcvbuf);
 
-       c->recv = NULL;
-       c->poll = NULL;
-
        switch(c->state) {
        case CLOSED:
                return true;
@@ -2127,8 +2124,8 @@ static void set_reapable(struct utcp_connection *c) {
        c->reapable = true;
 }
 
-// Closes all the opened connections
-void utcp_abort_all_connections(struct utcp *utcp) {
+// Resets all connections, but does not invalidate connection handles
+void utcp_reset_all_connections(struct utcp *utcp) {
        if(!utcp) {
                errno = EINVAL;
                return;
@@ -2141,19 +2138,16 @@ void utcp_abort_all_connections(struct utcp *utcp) {
                        continue;
                }
 
-               utcp_recv_t old_recv = c->recv;
-               utcp_poll_t old_poll = c->poll;
+               reset_connection(c);
 
-               utcp_abort(c);
-
-               if(old_recv) {
+               if(c->recv) {
                        errno = 0;
-                       old_recv(c, NULL, 0);
+                       c->recv(c, NULL, 0);
                }
 
-               if(old_poll && !c->reapable) {
+               if(c->poll && !c->reapable) {
                        errno = 0;
-                       old_poll(c, 0);
+                       c->poll(c, 0);
                }
        }
 
index 12964152420add6536efa500fcfd1d6ab709dc8d..5de9364b2ca447197ec0906c28eaaf454f5f11fd 100644 (file)
@@ -80,7 +80,7 @@ void utcp_set_recv_cb(struct utcp_connection *connection, utcp_recv_t recv);
 void utcp_set_poll_cb(struct utcp_connection *connection, utcp_poll_t poll);
 void utcp_set_accept_cb(struct utcp *utcp, utcp_accept_t accept, utcp_listen_t listen);
 bool utcp_is_active(struct utcp *utcp);
-void utcp_abort_all_connections(struct utcp *utcp);
+void utcp_reset_all_connections(struct utcp *utcp);
 
 // Global socket options