From 5487476fd919703b55cb1f1544d575224c9b685e Mon Sep 17 00:00:00 2001 From: David Goulet Date: Mon, 31 Jul 2023 10:57:34 -0400 Subject: [PATCH] Nullify on_circuit if last conflux leg Signed-off-by: David Goulet --- src/core/or/conflux_pool.c | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/core/or/conflux_pool.c b/src/core/or/conflux_pool.c index 79fd6c1648..837c1da720 100644 --- a/src/core/or/conflux_pool.c +++ b/src/core/or/conflux_pool.c @@ -1509,6 +1509,49 @@ linked_update_stream_backpointers(circuit_t *circ) } } +/** This is called when this circuit is the last leg. + * + * The "on_circuit" pointer is nullified here so it is not given back to the + * conflux subsytem between the circuit mark for close step and actually + * freeing the circuit which is when streams are destroyed. + * + * Reason is that when the connection edge inbuf is packaged in + * connection_edge_package_raw_inbuf(), the on_circuit pointer is used and + * then passed on to conflux to learn which leg to use. However, if the circuit + * was marked prior but not yet freed, there are no more legs remaining which + * leads to a linked circuit being used without legs. No bueno. */ +static void +linked_detach_circuit(circuit_t *circ) +{ + tor_assert(circ); + tor_assert_nonfatal(circ->conflux); + + if (CIRCUIT_IS_ORIGIN(circ)) { + origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); + tor_assert_nonfatal(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED); + /* Iterate over stream list using next_stream pointer, until null */ + for (edge_connection_t *stream = ocirc->p_streams; stream; + stream = stream->next_stream) { + /* Update the circuit pointer of each stream */ + stream->on_circuit = NULL; + } + } else { + or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); + /* Iterate over stream list using next_stream pointer, until null */ + for (edge_connection_t *stream = orcirc->n_streams; stream; + stream = stream->next_stream) { + /* Update the circuit pointer of each stream */ + stream->on_circuit = NULL; + } + /* Iterate over stream list using next_stream pointer, until null */ + for (edge_connection_t *stream = orcirc->resolving_streams; stream; + stream = stream->next_stream) { + /* Update the circuit pointer of each stream */ + stream->on_circuit = NULL; + } + } +} + /** Nullify all streams of the given circuit. */ static void linked_nullify_streams(circuit_t *circ) @@ -1549,6 +1592,7 @@ linked_circuit_closed(circuit_t *circ) if (CONFLUX_NUM_LEGS(circ->conflux) == 0) { /* Last leg, remove conflux object from linked set. */ linked_pool_del(circ->conflux->nonce, is_client); + linked_detach_circuit(circ); } else { /* If there are other circuits, update streams backpointers and * nullify the stream lists. We do not free those streams in circuit_free_.