tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

commit ba6db4ce97c3f654ee33b0abeb0f12ba6acc96af
parent 194e2dd2c269d535e1ea287acf015bc114c30bf0
Author: David Goulet <dgoulet@torproject.org>
Date:   Thu, 30 Oct 2025 12:01:04 -0400

conflux: Handle sequence number computation above 32 bit

This, theoritically, can be triggered in normal circumstances after around
2.2TB of data transfered on a circuit but apart from changing the protocol, we
can't fix that for now so bail out if reached.

Signed-off-by: David Goulet <dgoulet@torproject.org>

Diffstat:
Msrc/core/or/conflux.c | 8+++++++-
Msrc/core/or/conflux_cell.c | 13++++++++++++-
Msrc/core/or/relay.c | 8+++++++-
3 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/src/core/or/conflux.c b/src/core/or/conflux.c @@ -521,7 +521,13 @@ conflux_decide_circ_for_send(conflux_t *cfx, return NULL; } - conflux_send_switch_command(cfx->curr_leg->circ, relative_seq); + /* On failure to send the SWITCH, we close everything. This means we have + * a protocol error or the sending failed and the circuit is closed. */ + if (!conflux_send_switch_command(cfx->curr_leg->circ, relative_seq)) { + conflux_mark_all_for_close(cfx->nonce, CIRCUIT_IS_ORIGIN(new_circ), + END_CIRC_REASON_TORPROTOCOL); + return NULL; + } cfx->curr_leg->last_seq_sent = cfx->prev_leg->last_seq_sent; } } diff --git a/src/core/or/conflux_cell.c b/src/core/or/conflux_cell.c @@ -315,7 +315,18 @@ conflux_send_switch_command(circuit_t *send_circ, uint64_t relative_seq) bool ret = true; tor_assert(send_circ); - tor_assert(relative_seq < UINT32_MAX); + + /* This is possible unfortunately because the sequence numbers are 64 bit + * while in the SWITCH it is 32 bit. It would require more than 2.2 TB of + * data to be transfered on a circuit to reach this. Worth avoiding. */ + if (relative_seq >= UINT32_MAX) { + /* Avoid spamming logs with this, every hours should be fine. */ + static ratelim_t rlimit = RATELIM_INIT(60 * 60); + log_fn_ratelim(&rlimit, LOG_WARN, LD_CIRC, + "Relative sequence number is too high. Closing circuit."); + ret = false; + goto end; + } memset(&cell, 0, sizeof(cell)); diff --git a/src/core/or/relay.c b/src/core/or/relay.c @@ -640,7 +640,7 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *orig_circ, if (orig_circ->conflux && conflux_should_multiplex(relay_command)) { circ = conflux_decide_circ_for_send(orig_circ->conflux, orig_circ, relay_command); - if (BUG(!circ)) { + if (!circ) { log_warn(LD_BUG, "No circuit to send for conflux for relay command %d, " "called from %s:%d", relay_command, filename, lineno); conflux_log_set(LOG_WARN, orig_circ->conflux, @@ -654,6 +654,12 @@ relay_send_command_from_edge_,(streamid_t stream_id, circuit_t *orig_circ, } } + /* This is possible because we have protocol error paths when deciding the + * next circuit to send which can close the whole set. Bail out early. */ + if (circ->marked_for_close) { + return -1; + } + /* XXXX NM Split this function into a separate versions per circuit type? */ tor_assert(circ);