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:
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);