diff --git a/changes/ticket30871 b/changes/ticket30871 new file mode 100644 index 0000000000..81c076bb02 --- /dev/null +++ b/changes/ticket30871 @@ -0,0 +1,6 @@ + o Major bugfixes (circuit build, guard): + - When considering upgrading circuits from "waiting for guard" to "open", + always ignore the ones that are mark for close. Else, we can end up in + the situation where a subsystem is notified of that circuit opening but + still marked for close leading to undesirable behavior. Fixes bug 30871; + bugfix on 0.3.0.1-alpha. diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt index db9bf34e25..9073f2f1dd 100644 --- a/scripts/maint/practracker/exceptions.txt +++ b/scripts/maint/practracker/exceptions.txt @@ -135,8 +135,8 @@ problem function-size /src/feature/client/addressmap.c:addressmap_rewrite() 112 problem function-size /src/feature/client/bridges.c:rewrite_node_address_for_bridge() 126 problem function-size /src/feature/client/circpathbias.c:pathbias_measure_close_rate() 108 problem function-size /src/feature/client/dnsserv.c:evdns_server_callback() 153 -problem file-size /src/feature/client/entrynodes.c 3820 -problem function-size /src/feature/client/entrynodes.c:entry_guards_upgrade_waiting_circuits() 153 +problem file-size /src/feature/client/entrynodes.c 3824 +problem function-size /src/feature/client/entrynodes.c:entry_guards_upgrade_waiting_circuits() 157 problem function-size /src/feature/client/entrynodes.c:entry_guard_parse_from_state() 246 problem function-size /src/feature/client/transports.c:handle_proxy_line() 108 problem function-size /src/feature/client/transports.c:parse_method_line_helper() 112 diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c index 4afcee2021..54a9238d8f 100644 --- a/src/feature/client/entrynodes.c +++ b/src/feature/client/entrynodes.c @@ -2611,6 +2611,10 @@ entry_guards_upgrade_waiting_circuits(guard_selection_t *gs, entry_guard_t *guard = entry_guard_handle_get(state->guard); if (!guard || guard->in_selection != gs) continue; + if (TO_CIRCUIT(circ)->marked_for_close) { + /* Don't consider any marked for close circuits. */ + continue; + } smartlist_add(all_circuits, circ); } SMARTLIST_FOREACH_END(circ); diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c index 47218a559a..0c23091594 100644 --- a/src/test/test_circuitbuild.c +++ b/src/test/test_circuitbuild.c @@ -4,6 +4,8 @@ /* See LICENSE for licensing information */ #define CIRCUITBUILD_PRIVATE +#define CIRCUITLIST_PRIVATE +#define ENTRYNODES_PRIVATE #include "core/or/or.h" #include "test/test.h" @@ -13,7 +15,11 @@ #include "core/or/circuitbuild.h" #include "core/or/circuitlist.h" +#include "core/or/cpath_build_state_st.h" #include "core/or/extend_info_st.h" +#include "core/or/origin_circuit_st.h" + +#include "feature/client/entrynodes.h" /* Dummy nodes smartlist for testing */ static smartlist_t dummy_nodes; @@ -126,10 +132,51 @@ test_new_route_len_unhandled_exit(void *arg) UNMOCK(count_acceptable_nodes); } +static void +test_upgrade_from_guard_wait(void *arg) +{ + circuit_t *circ = NULL; + origin_circuit_t *orig_circ = NULL; + entry_guard_t *guard = NULL; + smartlist_t *list = NULL; + + (void) arg; + + circ = dummy_origin_circuit_new(0); + orig_circ = TO_ORIGIN_CIRCUIT(circ); + tt_assert(orig_circ); + + orig_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); + + circuit_set_state(circ, CIRCUIT_STATE_GUARD_WAIT); + + /* Put it in guard wait state. */ + guard = tor_malloc_zero(sizeof(*guard)); + guard->in_selection = get_guard_selection_info(); + + orig_circ->guard_state = + circuit_guard_state_new(guard, GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD, + NULL); + + /* Mark the circuit for close. */ + circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL); + tt_int_op(circ->marked_for_close, OP_NE, 0); + + /* We shouldn't pick the mark for close circuit. */ + list = circuit_find_circuits_to_upgrade_from_guard_wait(); + tt_assert(!list); + + done: + circuit_free(circ); + entry_guard_free_(guard); +} + struct testcase_t circuitbuild_tests[] = { { "noexit", test_new_route_len_noexit, 0, NULL, NULL }, { "safe_exit", test_new_route_len_safe_exit, 0, NULL, NULL }, { "unsafe_exit", test_new_route_len_unsafe_exit, 0, NULL, NULL }, { "unhandled_exit", test_new_route_len_unhandled_exit, 0, NULL, NULL }, + { "upgrade_from_guard_wait", test_upgrade_from_guard_wait, TT_FORK, + NULL, NULL }, END_OF_TESTCASES };