From 2bd86439e6cee8742a01bb715461be62f6d33ac8 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Tue, 4 May 2021 21:51:50 +0200 Subject: [PATCH] Fix potential incorrect destruction of channels. 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 | 2 +- src/meshlink.c | 2 +- src/utcp.c | 20 +++++++------------- src/utcp.h | 2 +- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/graph.c b/src/graph.c index c7401b6a..9a2bfb19 100644 --- a/src/graph.c +++ b/src/graph.c @@ -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; diff --git a/src/meshlink.c b/src/meshlink.c index 5d5733e7..fe11af2c 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -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; diff --git a/src/utcp.c b/src/utcp.c index fa45e9c6..ca91bee2 100644 --- a/src/utcp.c +++ b/src/utcp.c @@ -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); } } diff --git a/src/utcp.h b/src/utcp.h index 12964152..5de9364b 100644 --- a/src/utcp.h +++ b/src/utcp.h @@ -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 -- 2.39.2