From 7c085490f5324f374dd7caa570dff5902f0e32cc Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 5 Nov 2021 09:15:10 -0400 Subject: [PATCH 1/5] Add scary warnings about changing the protover list. Doing this in the wrong way has potential to cause serious havoc on the network, so let's make it harder for future programmers to mess it up. --- src/core/or/protover.c | 22 +++++++++++++++++++++- src/feature/dirauth/dirvote.c | 26 ++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/core/or/protover.c b/src/core/or/protover.c index dfb0e9e303..a882d1a77d 100644 --- a/src/core/or/protover.c +++ b/src/core/or/protover.c @@ -377,11 +377,31 @@ protocol_list_supports_protocol_or_later(const char *list, } /** Return the canonical string containing the list of protocols - * that we support. */ + * that we support. + **/ /// C_RUST_COUPLED: src/rust/protover/protover.rs `SUPPORTED_PROTOCOLS` const char * protover_get_supported_protocols(void) { + /* + * WARNING! + * + * Be EXTREMELY CAREFUL when *removing* versions from this list. If you + * remove an entry while it still appears as "recommended" in the consensus, + * you'll cause all the instances without it to warn. If you remove an entry + * while it still appears as "required" in the consensus, you'll cause + * all the instances without it to refuse to connect to the network, and + * shut down. + * + * If you need to remove a version from this list, you need to make sure + * that it is not listed in the _current consensuses_: just removing it from + * the required list in dirvote.c is NOT ENOUGH. You need to remove it from + * the required list dirvote.c, and THEN let the authorities update and vote + * on new consensuses without it. Only once those consensuses are out is + * it safe to remove from this list. + * + * WARNING! + */ return "Cons=1-2 " "Desc=1-2 " diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c index 9e01cee42a..5ecf680f02 100644 --- a/src/feature/dirauth/dirvote.c +++ b/src/feature/dirauth/dirvote.c @@ -180,7 +180,7 @@ format_protocols_lines_for_vote(const networkstatus_t *v3_ns) char *required_relay_protocols_line = NULL; char *required_client_protocols_line = NULL; - recommended_relay_protocols_line = + recommended_relay_protocols_line = format_line_if_present("recommended-relay-protocols", v3_ns->recommended_relay_protocols); recommended_client_protocols_line = @@ -4577,7 +4577,29 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, v3_out->client_versions = client_versions; v3_out->server_versions = server_versions; - /* These are hardwired, to avoid disaster. */ + /* + * WARNING! + * + * These values are hardwired, to avoid disaster. Voting on the wrong + * subprotocols here has the potential to take down the network. + * + * In particular, you need to be EXTREMELY CAREFUL before adding new + * versions to the required protocol list. Doing so will cause every relay + * or client that doesn't support those versions to refuse to connect to the + * network and shut down. + * + * Note that this applies to versions, not just protocols! If you say that + * Foobar=8-9 is required, and the client only has Foobar=9, it will shut + * down. + * + * It is okay to do this only for SUPER OLD relays that are not supported on + * the network anyway. For clients, we really shouldn't kick them off the + * network unless their presence is causing serious active harm. + * + * See also the warning in protocol_get_supported_versions(). + * + * WARNING! + */ v3_out->recommended_relay_protocols = tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " "Link=4 Microdesc=1-2 Relay=2"); From 3d1a49908c2727746928d40bc71da0373aad7fcf Mon Sep 17 00:00:00 2001 From: David Goulet Date: Fri, 5 Nov 2021 10:10:24 -0400 Subject: [PATCH 2/5] protover: Move all hardcoded lists in one place This also moves the warnings and add some theatrical effect around the code so anyone modifying those list should notice the warnings signs and read the comment accordingly. Signed-off-by: David Goulet --- src/core/or/protover.c | 107 ++++++++++++++++++++++++++++++---- src/core/or/protover.h | 4 ++ src/feature/dirauth/dirvote.c | 37 ++---------- 3 files changed, 104 insertions(+), 44 deletions(-) diff --git a/src/core/or/protover.c b/src/core/or/protover.c index a882d1a77d..0183704c2c 100644 --- a/src/core/or/protover.c +++ b/src/core/or/protover.c @@ -376,6 +376,10 @@ protocol_list_supports_protocol_or_later(const char *list, return contains; } +/* + * XXX START OF HAZARDOUS ZONE XXX + */ + /** Return the canonical string containing the list of protocols * that we support. **/ @@ -383,25 +387,37 @@ protocol_list_supports_protocol_or_later(const char *list, const char * protover_get_supported_protocols(void) { + /* - * WARNING! + * XXX: WARNING! * * Be EXTREMELY CAREFUL when *removing* versions from this list. If you * remove an entry while it still appears as "recommended" in the consensus, - * you'll cause all the instances without it to warn. If you remove an entry - * while it still appears as "required" in the consensus, you'll cause - * all the instances without it to refuse to connect to the network, and - * shut down. + * you'll cause all the instances without it to warn. * - * If you need to remove a version from this list, you need to make sure - * that it is not listed in the _current consensuses_: just removing it from - * the required list in dirvote.c is NOT ENOUGH. You need to remove it from - * the required list dirvote.c, and THEN let the authorities update and vote - * on new consensuses without it. Only once those consensuses are out is - * it safe to remove from this list. + * If you remove an entry while it still appears as "required" in the + * consensus, you'll cause all the instances without it to refuse to connect + * to the network, and shut down. * - * WARNING! + * If you need to remove a version from this list, you need to make sure that + * it is not listed in the _current consensuses_: just removing it from the + * required list below is NOT ENOUGH. You need to remove it from the + * required list, and THEN let the authorities update and vote on new + * consensuses without it. Only once those consensuses are out is it safe to + * remove from this list. + * + * One concrete example of a very dangerous race that could occur: + * + * If the client required protocol "HSDir=1-2" is then changed in the code + * and released to "HSDir=2" while the consensus stills lists "HSDir=1-2", + * then these clients, even very recent ones, will shutdown because they + * don't support "HSDir=1". + * + * And so, changes need to be done in lockstep as described above. + * + * XXX: WARNING! */ + return "Cons=1-2 " "Desc=1-2 " @@ -419,6 +435,73 @@ protover_get_supported_protocols(void) "Relay=1-2"; } +/* + * XXX: WARNING! + * + * The recommended and required values are hardwired, to avoid disaster. Voting + * on the wrong subprotocols here has the potential to take down the network. + * + * In particular, you need to be EXTREMELY CAREFUL before adding new versions + * to the required protocol list. Doing so will cause every relay or client + * that doesn't support those versions to refuse to connect to the network and + * shut down. + * + * Note that this applies to versions, not just protocols! If you say that + * Foobar=8-9 is required, and the client only has Foobar=9, it will shut down. + * + * It is okay to do this only for SUPER OLD relays that are not supported on + * the network anyway. For clients, we really shouldn't kick them off the + * network unless their presence is causing serious active harm. + * + * The following required and recommended lists MUST be changed BEFORE the + * supported list above is changed in order for those lists to appear in the + * consensus BEFORE. + * + * Please, see the warning in protocol_get_supported_versions(). + * + * XXX: WARNING! + */ + +/** Return the recommended client protocols list that directory authorities + * put in the consensus. */ +const char * +protover_get_recommended_client_protocols(void) +{ + return "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " + "Link=4 Microdesc=1-2 Relay=2"; +} + +/** Return the recommended relay protocols list that directory authorities + * put in the consensus. */ +const char * +protover_get_recommended_relay_protocols(void) +{ + return "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " + "Link=4 Microdesc=1-2 Relay=2"; +} + +/** Return the required client protocols list that directory authorities + * put in the consensus. */ +const char * +protover_get_required_client_protocols(void) +{ + return "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " + "Link=4 Microdesc=1-2 Relay=2"; +} + +/** Return the required relay protocols list that directory authorities + * put in the consensus. */ +const char * +protover_get_required_relay_protocols(void) +{ + return "Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " + "Link=3-4 Microdesc=1 Relay=1-2"; +} + +/* + * XXX END OF HAZARDOUS ZONE XXX + */ + /** The protocols from protover_get_supported_protocols(), as parsed into a * list of proto_entry_t values. Access this via * get_supported_protocol_list. */ diff --git a/src/core/or/protover.h b/src/core/or/protover.h index 7e181ba97a..c99dfe40ae 100644 --- a/src/core/or/protover.h +++ b/src/core/or/protover.h @@ -49,6 +49,10 @@ bool protover_contains_long_protocol_names(const char *s); int protover_all_supported(const char *s, char **missing); int protover_is_supported_here(protocol_type_t pr, uint32_t ver); const char *protover_get_supported_protocols(void); +const char *protover_get_recommended_client_protocols(void); +const char *protover_get_recommended_relay_protocols(void); +const char *protover_get_required_client_protocols(void); +const char *protover_get_required_relay_protocols(void); char *protover_compute_vote(const struct smartlist_t *list_of_proto_strings, int threshold); diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c index 5ecf680f02..d6a99d3ef8 100644 --- a/src/feature/dirauth/dirvote.c +++ b/src/feature/dirauth/dirvote.c @@ -180,7 +180,7 @@ format_protocols_lines_for_vote(const networkstatus_t *v3_ns) char *required_relay_protocols_line = NULL; char *required_client_protocols_line = NULL; - recommended_relay_protocols_line = + recommended_relay_protocols_line = format_line_if_present("recommended-relay-protocols", v3_ns->recommended_relay_protocols); recommended_client_protocols_line = @@ -4577,41 +4577,14 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, v3_out->client_versions = client_versions; v3_out->server_versions = server_versions; - /* - * WARNING! - * - * These values are hardwired, to avoid disaster. Voting on the wrong - * subprotocols here has the potential to take down the network. - * - * In particular, you need to be EXTREMELY CAREFUL before adding new - * versions to the required protocol list. Doing so will cause every relay - * or client that doesn't support those versions to refuse to connect to the - * network and shut down. - * - * Note that this applies to versions, not just protocols! If you say that - * Foobar=8-9 is required, and the client only has Foobar=9, it will shut - * down. - * - * It is okay to do this only for SUPER OLD relays that are not supported on - * the network anyway. For clients, we really shouldn't kick them off the - * network unless their presence is causing serious active harm. - * - * See also the warning in protocol_get_supported_versions(). - * - * WARNING! - */ v3_out->recommended_relay_protocols = - tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=4 Microdesc=1-2 Relay=2"); + tor_strdup(protover_get_recommended_relay_protocols()); v3_out->recommended_client_protocols = - tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=4 Microdesc=1-2 Relay=2"); + tor_strdup(protover_get_recommended_client_protocols()); v3_out->required_client_protocols = - tor_strdup("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=4 Microdesc=1-2 Relay=2"); + tor_strdup(protover_get_required_client_protocols()); v3_out->required_relay_protocols = - tor_strdup("Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=3-4 Microdesc=1 Relay=1-2"); + tor_strdup(protover_get_required_relay_protocols()); /* We are not allowed to vote to require anything we don't have. */ tor_assert(protover_all_supported(v3_out->required_relay_protocols, NULL)); From f93cd5deb8f4731920043016c082e44e81afcfbf Mon Sep 17 00:00:00 2001 From: David Goulet Date: Fri, 5 Nov 2021 10:16:08 -0400 Subject: [PATCH 3/5] protover: Add a note on why LinkAuth is not recommended or required Signed-off-by: David Goulet --- src/core/or/protover.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/core/or/protover.c b/src/core/or/protover.c index 0183704c2c..8075dd425c 100644 --- a/src/core/or/protover.c +++ b/src/core/or/protover.c @@ -462,6 +462,13 @@ protover_get_supported_protocols(void) * XXX: WARNING! */ +/* + * NOTE: A keen observer will notice that "LinkAuth" is not recommended nor + * required. This is due to the HAVE_WORKING_TOR_TLS_GET_TLSSECRETS define + * that can either set "1" or "1,3" and so we can't enforce one or the other + * due to this uncertainty on how tor was built. + */ + /** Return the recommended client protocols list that directory authorities * put in the consensus. */ const char * From 439e17180c362962abfdf2301dddbdaa323df24a Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 5 Nov 2021 10:30:57 -0400 Subject: [PATCH 4/5] Light edit to protover warnings. --- src/core/or/protover.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/core/or/protover.c b/src/core/or/protover.c index 8075dd425c..82e4f64c94 100644 --- a/src/core/or/protover.c +++ b/src/core/or/protover.c @@ -402,18 +402,19 @@ protover_get_supported_protocols(void) * If you need to remove a version from this list, you need to make sure that * it is not listed in the _current consensuses_: just removing it from the * required list below is NOT ENOUGH. You need to remove it from the - * required list, and THEN let the authorities update and vote on new + * required list, and THEN let the authorities upgrade and vote on new * consensuses without it. Only once those consensuses are out is it safe to * remove from this list. * * One concrete example of a very dangerous race that could occur: * - * If the client required protocol "HSDir=1-2" is then changed in the code - * and released to "HSDir=2" while the consensus stills lists "HSDir=1-2", - * then these clients, even very recent ones, will shutdown because they + * Suppose that the client supports protocols "HsDir=1-2" and the consensus + * requires protocols "HsDir=1-2. If the client supported protocol list is + * then changed to "HSDir=2", while the consensus stills lists "HSDir=1-2", + * then these clients, even very recent ones, will shut down because they * don't support "HSDir=1". * - * And so, changes need to be done in lockstep as described above. + * And so, changes need to be done in strict sequence as described above. * * XXX: WARNING! */ @@ -454,8 +455,8 @@ protover_get_supported_protocols(void) * network unless their presence is causing serious active harm. * * The following required and recommended lists MUST be changed BEFORE the - * supported list above is changed in order for those lists to appear in the - * consensus BEFORE. + * supported list above is changed, so that these lists appear in the + * consensus BEFORE clients need them. * * Please, see the warning in protocol_get_supported_versions(). * From a7fe37f1fa7821d0bdbeabe480df8aba7dc1fded Mon Sep 17 00:00:00 2001 From: David Goulet Date: Fri, 5 Nov 2021 10:42:54 -0400 Subject: [PATCH 5/5] protover: Fix merge forward from 035 Signed-off-by: David Goulet --- src/core/or/protover.c | 22 +++++-------- src/feature/dirauth/dirvote.h | 58 ----------------------------------- src/test/test_protover.c | 8 ++--- 3 files changed, 11 insertions(+), 77 deletions(-) diff --git a/src/core/or/protover.c b/src/core/or/protover.c index 8b307a8a2f..cb9a03d6ec 100644 --- a/src/core/or/protover.c +++ b/src/core/or/protover.c @@ -478,20 +478,13 @@ protover_get_supported_protocols(void) * XXX: WARNING! */ -/* - * NOTE: A keen observer will notice that "LinkAuth" is not recommended nor - * required. This is due to the HAVE_WORKING_TOR_TLS_GET_TLSSECRETS define - * that can either set "1" or "1,3" and so we can't enforce one or the other - * due to this uncertainty on how tor was built. - */ - /** Return the recommended client protocols list that directory authorities * put in the consensus. */ const char * protover_get_recommended_client_protocols(void) { - return "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=4 Microdesc=1-2 Relay=2"; + return "Cons=2 Desc=2 DirCache=2 HSDir=2 HSIntro=4 HSRend=2 " + "Link=4-5 Microdesc=2 Relay=2"; } /** Return the recommended relay protocols list that directory authorities @@ -499,8 +492,8 @@ protover_get_recommended_client_protocols(void) const char * protover_get_recommended_relay_protocols(void) { - return "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=4 Microdesc=1-2 Relay=2"; + return "Cons=2 Desc=2 DirCache=2 HSDir=2 HSIntro=4 HSRend=2 " + "Link=4-5 LinkAuth=3 Microdesc=2 Relay=2"; } /** Return the required client protocols list that directory authorities @@ -508,8 +501,7 @@ protover_get_recommended_relay_protocols(void) const char * protover_get_required_client_protocols(void) { - return "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=4 Microdesc=1-2 Relay=2"; + return "Cons=2 Desc=2 Link=4 Microdesc=2 Relay=2"; } /** Return the required relay protocols list that directory authorities @@ -517,8 +509,8 @@ protover_get_required_client_protocols(void) const char * protover_get_required_relay_protocols(void) { - return "Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 " - "Link=3-4 Microdesc=1 Relay=1-2"; + return "Cons=2 Desc=2 DirCache=2 HSDir=2 HSIntro=4 HSRend=2 " + "Link=4-5 LinkAuth=3 Microdesc=2 Relay=2"; } /* diff --git a/src/feature/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h index f9441773a7..81a7733e8c 100644 --- a/src/feature/dirauth/dirvote.h +++ b/src/feature/dirauth/dirvote.h @@ -260,64 +260,6 @@ char *networkstatus_get_detached_signatures(smartlist_t *consensuses); STATIC microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method); -/** The recommended relay protocols for this authority's votes. - * Recommending a new protocol causes old tor versions to log a warning. - */ -#define DIRVOTE_RECOMMEND_RELAY_PROTO \ - "Cons=2 " \ - "Desc=2 " \ - "DirCache=2 " \ - "HSDir=2 " \ - "HSIntro=4 " \ - "HSRend=2 " \ - "Link=4-5 " \ - "LinkAuth=3 " \ - "Microdesc=2 " \ - "Relay=2" - -/** The recommended client protocols for this authority's votes. - * Recommending a new protocol causes old tor versions to log a warning. - */ -#define DIRVOTE_RECOMMEND_CLIENT_PROTO \ - "Cons=2 " \ - "Desc=2 " \ - "DirCache=2 " \ - "HSDir=2 " \ - "HSIntro=4 " \ - "HSRend=2 " \ - "Link=4-5 " \ - "Microdesc=2 " \ - "Relay=2" - -/** The required relay protocols for this authority's votes. - * WARNING: Requiring a new protocol causes old tor versions to shut down. - * Requiring the wrong protocols can break the tor network. - * See Proposal 303: When and how to remove support for protocol versions. - */ -#define DIRVOTE_REQUIRE_RELAY_PROTO \ - "Cons=2 " \ - "Desc=2 " \ - "DirCache=2 " \ - "HSDir=2 " \ - "HSIntro=4 " \ - "HSRend=2 " \ - "Link=4-5 " \ - "LinkAuth=3 " \ - "Microdesc=2 " \ - "Relay=2" - -/** The required relay protocols for this authority's votes. - * WARNING: Requiring a new protocol causes old tor versions to shut down. - * Requiring the wrong protocols can break the tor network. - * See Proposal 303: When and how to remove support for protocol versions. - */ -#define DIRVOTE_REQUIRE_CLIENT_PROTO \ - "Cons=2 " \ - "Desc=2 " \ - "Link=4 " \ - "Microdesc=2 " \ - "Relay=2" - #endif /* defined(DIRVOTE_PRIVATE) */ #endif /* !defined(TOR_DIRVOTE_H) */ diff --git a/src/test/test_protover.c b/src/test/test_protover.c index dd65f4bbf5..016cee7f15 100644 --- a/src/test/test_protover.c +++ b/src/test/test_protover.c @@ -606,10 +606,10 @@ test_protover_vote_roundtrip_ours(void *args) (void) args; const char *examples[] = { protover_get_supported_protocols(), - DIRVOTE_RECOMMEND_RELAY_PROTO, - DIRVOTE_RECOMMEND_CLIENT_PROTO, - DIRVOTE_REQUIRE_RELAY_PROTO, - DIRVOTE_REQUIRE_CLIENT_PROTO, + protover_get_recommended_client_protocols(), + protover_get_recommended_relay_protocols(), + protover_get_required_client_protocols(), + protover_get_required_relay_protocols(), }; unsigned u; smartlist_t *votes = smartlist_new();