From d02eb4502a7798780262e091affab7718a14f3d6 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Wed, 6 Dec 2023 17:12:43 +0000 Subject: Bug 40897: Move safety check to proper location and give it error handling. --- src/core/or/conflux_pool.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/core/or/conflux_pool.c b/src/core/or/conflux_pool.c index 3a8f6ec8e3..a9bd970aa1 100644 --- a/src/core/or/conflux_pool.c +++ b/src/core/or/conflux_pool.c @@ -493,10 +493,6 @@ cfx_add_leg(conflux_t *cfx, leg_t *leg) /* Big trouble if we add a leg to the wrong set. */ tor_assert(tor_memeq(cfx->nonce, leg->link->nonce, sizeof(cfx->nonce))); - if (BUG(CONFLUX_NUM_LEGS(cfx) > CONFLUX_MAX_CIRCS)) { - return; - } - conflux_leg_t *cleg = tor_malloc_zero(sizeof(*cleg)); cleg->circ = leg->circ; // TODO-329-ARTI: Blindly copying the values from the cell. Is this correct? @@ -731,6 +727,9 @@ try_finalize_set(unlinked_circuits_t *unlinked) bool is_client; tor_assert(unlinked); + tor_assert(unlinked->legs); + tor_assert(unlinked->cfx); + tor_assert(unlinked->cfx->legs); /* Without legs, this is not ready to become a linked set. */ if (BUG(smartlist_len(unlinked->legs) == 0)) { @@ -738,6 +737,17 @@ try_finalize_set(unlinked_circuits_t *unlinked) goto end; } + /* If there are too many legs, we can't link. */ + if (smartlist_len(unlinked->legs) + + smartlist_len(unlinked->cfx->legs) > CONFLUX_MAX_CIRCS) { + log_fn(LOG_PROTOCOL_WARN, LD_CIRC, + "Conflux set has too many legs to link. " + "Rejecting this circuit."); + conflux_log_set(LOG_PROTOCOL_WARN, unlinked->cfx, unlinked->is_client); + err = ERR_LINK_CIRC_INVALID_LEG; + goto end; + } + /* Validate that all legs are coherent and parameters match. On failure, we * teardown the whole unlinked set because this means we either have a code * flow problem or the Exit is trying to trick us. */ -- cgit v1.2.3-54-g00ecf From 03778a0f3489994e78de70c7c5cd69f570329fab Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Wed, 6 Dec 2023 18:54:59 +0000 Subject: Bug 40897: Add more checks to free paths Similar double-frees would be caught earlier by these, so long as the pointers remain nulled out. --- src/core/or/conflux.c | 2 ++ src/core/or/conflux_pool.c | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/core/or/conflux.c b/src/core/or/conflux.c index 0a2806b1dc..677df95067 100644 --- a/src/core/or/conflux.c +++ b/src/core/or/conflux.c @@ -115,6 +115,8 @@ conflux_leg_t * conflux_get_leg(conflux_t *cfx, const circuit_t *circ) { conflux_leg_t *leg_found = NULL; + tor_assert(cfx); + tor_assert(cfx->legs); // Find the leg that the cell is written on CONFLUX_FOR_EACH_LEG_BEGIN(cfx, leg) { diff --git a/src/core/or/conflux_pool.c b/src/core/or/conflux_pool.c index a9bd970aa1..5a677fb9aa 100644 --- a/src/core/or/conflux_pool.c +++ b/src/core/or/conflux_pool.c @@ -187,6 +187,8 @@ conflux_free_(conflux_t *cfx) if (!cfx) { return; } + tor_assert(cfx->legs); + tor_assert(cfx->ooo_q); SMARTLIST_FOREACH_BEGIN(cfx->legs, conflux_leg_t *, leg) { SMARTLIST_DEL_CURRENT(cfx->legs, leg); @@ -260,6 +262,8 @@ unlinked_free(unlinked_circuits_t *unlinked) if (!unlinked) { return; } + tor_assert(unlinked->legs); + /* This cfx is pointing to a linked set. */ if (!unlinked->is_for_linked_set) { conflux_free(unlinked->cfx); @@ -1611,6 +1615,9 @@ linked_circuit_free(circuit_t *circ, bool is_client) { tor_assert(circ); tor_assert(circ->conflux); + tor_assert(circ->conflux->legs); + tor_assert(circ->conflux->ooo_q); + if (is_client) { tor_assert(circ->purpose == CIRCUIT_PURPOSE_CONFLUX_LINKED); } -- cgit v1.2.3-54-g00ecf From cc52f7e5b72199a1f3278daa9e0db876bc86c973 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Wed, 6 Dec 2023 17:23:19 +0000 Subject: Bug 40897 Bug Bounty: Double the number of max conflux circs We strongly suspect that bug 40897 was caused by a custom Tor client that tried to use more than the default number of conflux circuits, for either performance or traffic analysis defense gains, or both. This entity hit a safety check on the exit side, which caused a UAF. Our "belt and suspenders" snapped off, and hit us in the face... again... Since there are good reasons to try more than 2 conflux legs, and research has found some traffic analysis benefits with as many as 5, we're going to raise and parameterize this limit as a form of bug bounty for finding this UAF, so that this entity can try out a little more confluxing. This should also make it easier for researchers to try things like gathering traces with larger amounts of confluxing than normal, to measure real-world traffic analysis impacts of conflux. Shine on, you yoloing anonymous diamond. Let us know if you find out anything interesting! --- src/core/or/conflux_params.c | 19 +++++++++++++++++++ src/core/or/conflux_params.h | 1 + src/core/or/conflux_pool.c | 2 +- src/core/or/conflux_st.h | 13 ------------- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/core/or/conflux_params.c b/src/core/or/conflux_params.c index dbf4ae5272..65728032f9 100644 --- a/src/core/or/conflux_params.c +++ b/src/core/or/conflux_params.c @@ -56,6 +56,11 @@ #define NUM_LEGS_SET_MAX (UINT8_MAX) #define NUM_LEGS_SET_DEFAULT (2) +/* For "cfx_max_legs_set" */ +#define MAX_LEGS_SET_MIN (3) +#define MAX_LEGS_SET_MAX (UINT8_MAX) +#define MAX_LEGS_SET_DEFAULT (8) + /* For "cfx_send_pct". */ #define CFX_SEND_PCT_MIN (0) #define CFX_SEND_PCT_MAX (255) @@ -81,6 +86,8 @@ static uint8_t max_prebuilt_set = MAX_PREBUILT_SET_DEFAULT; STATIC uint32_t max_unlinked_leg_retry = MAX_UNLINKED_LEG_RETRY_DEFAULT; /* Number of legs per set. */ static uint8_t num_legs_set = NUM_LEGS_SET_DEFAULT; +/* Maximum number of legs per set allowed at exits */ +static uint8_t max_legs_set = MAX_LEGS_SET_DEFAULT; /* The low Exit relay threshold, as a ratio between 0 and 1, used as a limit to * decide the amount of pre-built set we build depending on how many Exit relay * supports conflux in our current consensus. */ @@ -223,6 +230,13 @@ conflux_params_get_num_legs_set(void) return num_legs_set; } +/** Return the maximum number of legs per set. */ +uint8_t +conflux_params_get_max_legs_set(void) +{ + return max_legs_set; +} + /** Return the drain percent we must hit before switching */ uint8_t conflux_params_get_drain_pct(void) @@ -275,6 +289,11 @@ conflux_params_new_consensus(const networkstatus_t *ns) NUM_LEGS_SET_DEFAULT, NUM_LEGS_SET_MIN, NUM_LEGS_SET_MAX); + max_legs_set = + networkstatus_get_param(ns, "cfx_max_legs_set", + MAX_LEGS_SET_DEFAULT, + MAX_LEGS_SET_MIN, MAX_LEGS_SET_MAX); + /* Params used by conflux.c */ cfx_send_pct = networkstatus_get_param(ns, "cfx_send_pct", CFX_SEND_PCT_DFLT, diff --git a/src/core/or/conflux_params.h b/src/core/or/conflux_params.h index 22c3e4ad1f..06e902cf03 100644 --- a/src/core/or/conflux_params.h +++ b/src/core/or/conflux_params.h @@ -16,6 +16,7 @@ uint8_t conflux_params_get_max_linked_set(void); uint8_t conflux_params_get_max_prebuilt(void); uint8_t conflux_params_get_max_unlinked_leg_retry(void); uint8_t conflux_params_get_num_legs_set(void); +uint8_t conflux_params_get_max_legs_set(void); uint8_t conflux_params_get_drain_pct(void); uint8_t conflux_params_get_send_pct(void); diff --git a/src/core/or/conflux_pool.c b/src/core/or/conflux_pool.c index 5a677fb9aa..74781b307a 100644 --- a/src/core/or/conflux_pool.c +++ b/src/core/or/conflux_pool.c @@ -743,7 +743,7 @@ try_finalize_set(unlinked_circuits_t *unlinked) /* If there are too many legs, we can't link. */ if (smartlist_len(unlinked->legs) + - smartlist_len(unlinked->cfx->legs) > CONFLUX_MAX_CIRCS) { + smartlist_len(unlinked->cfx->legs) > conflux_params_get_max_legs_set()) { log_fn(LOG_PROTOCOL_WARN, LD_CIRC, "Conflux set has too many legs to link. " "Rejecting this circuit."); diff --git a/src/core/or/conflux_st.h b/src/core/or/conflux_st.h index 8d85ad1fbe..61e38f8268 100644 --- a/src/core/or/conflux_st.h +++ b/src/core/or/conflux_st.h @@ -22,19 +22,6 @@ typedef enum { CONFLUX_ALG_CWNDRTT = 2, } conflux_alg_t; -/** - * Maximum number of linked circuits. - * - * We want to experiment with 3 guards, so we need at least 3 here. - * - * However, we need 1 more than this, to support using a test circuit to probe - * for a faster path, for applications that *require* a specific latency target - * (like VoIP). - * - * We may also want to raise this for traffic analysis defense evaluation. - */ -#define CONFLUX_MAX_CIRCS 4 - /** XXX: Cached consensus params+scheduling alg */ struct conflux_params_t { conflux_alg_t alg; -- cgit v1.2.3-54-g00ecf From 97b4264f3995766b0e064d9a0f206534b832c6a3 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Wed, 6 Dec 2023 20:58:01 +0000 Subject: Bug 40897: Changes file --- changes/bug40897 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/bug40897 diff --git a/changes/bug40897 b/changes/bug40897 new file mode 100644 index 0000000000..0c41033c9d --- /dev/null +++ b/changes/bug40897 @@ -0,0 +1,6 @@ + o Major bugfixes (TROVE-2023-007, exit): + - Improper error propagation from a safety check in conflux leg + linking lead to a desynchronization of which legs were part of + a conflux set, ultimately causing a UAF and NULL pointer + dereference crash on Exit relays. Fixes bug 40897; + bugfix on 0.4.8.1-alpha. -- cgit v1.2.3-54-g00ecf