From 65f2eec694f18a64291cc85317b9f22dacc1d8e4 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 1 Feb 2018 16:33:52 -0500 Subject: Correctly handle NULL returns from parse_protocol_list when voting. In some cases we had checked for it, but in others we had not. One of these cases could have been used to remotely cause denial-of-service against directory authorities while they attempted to vote. Fixes TROVE-2018-001. --- changes/trove-2018-001.1 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/trove-2018-001.1 (limited to 'changes') diff --git a/changes/trove-2018-001.1 b/changes/trove-2018-001.1 new file mode 100644 index 0000000000..f0ee92f409 --- /dev/null +++ b/changes/trove-2018-001.1 @@ -0,0 +1,6 @@ + o Major bugfixes (denial-of-service, directory authority): + - Fix a protocol-list handling bug that could be used to remotely crash + directory authorities with a null-pointer exception. Fixes bug 25074; + bugfix on 0.2.9.4-alpha. Also tracked as TROVE-2018-001. + + -- cgit v1.2.3-54-g00ecf From a83650852d3cd00c9916cae74d755ae55a6b506d Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 14 Feb 2018 10:45:57 -0500 Subject: Add another NULL-pointer fix for protover.c. This one can only be exploited if you can generate a correctly signed consensus, so it's not as bad as 25074. Fixes bug 25251; also tracked as TROVE-2018-004. --- changes/trove-2018-004 | 8 ++++++++ src/or/protover.c | 5 +++++ 2 files changed, 13 insertions(+) create mode 100644 changes/trove-2018-004 (limited to 'changes') diff --git a/changes/trove-2018-004 b/changes/trove-2018-004 new file mode 100644 index 0000000000..37e0a89b0d --- /dev/null +++ b/changes/trove-2018-004 @@ -0,0 +1,8 @@ + o Minor bugfixes (denial-of-service): + - Fix a possible crash on malformed consensus. If a consensus had + contained an unparseable protocol line, it could have made clients + and relays crash with a null-pointer exception. To exploit this + issue, however, an attacker would need to be able to subvert the + directory-authority system. Fixes bug 25251; bugfix on + 0.2.9.4-alpha. Also tracked as TROVE-2018-004. + diff --git a/src/or/protover.c b/src/or/protover.c index a750774623..e63036f784 100644 --- a/src/or/protover.c +++ b/src/or/protover.c @@ -624,6 +624,11 @@ protover_all_supported(const char *s, char **missing_out) } smartlist_t *entries = parse_protocol_list(s); + if (BUG(entries == NULL)) { + log_warn(LD_NET, "Received an unparseable protocol list %s" + " from the consensus", escaped(s)); + return 1; + } missing = smartlist_new(); -- cgit v1.2.3-54-g00ecf From 8b405c609e82fbfb5470967fc4c45165c708e72b Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 15 Feb 2018 08:46:13 -0500 Subject: Forbid "-0" as a protocol version. Fixes part of 24249; bugfix on 0.2.9.4-alpha. --- changes/bug25249 | 3 +++ src/or/protover.c | 9 +++++++++ src/test/test_protover.c | 6 ++++-- 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 changes/bug25249 (limited to 'changes') diff --git a/changes/bug25249 b/changes/bug25249 new file mode 100644 index 0000000000..b4153eeaef --- /dev/null +++ b/changes/bug25249 @@ -0,0 +1,3 @@ + o Minor bugfixes (spec conformance): + - Forbid "-0" as a protocol version. Fixes part of bug 25249; bugfix on + 0.2.9.4-alpha. diff --git a/src/or/protover.c b/src/or/protover.c index e63036f784..f32316f8e7 100644 --- a/src/or/protover.c +++ b/src/or/protover.c @@ -123,6 +123,11 @@ parse_version_range(const char *s, const char *end_of_range, if (BUG(!end_of_range)) end_of_range = s + strlen(s); // LCOV_EXCL_LINE + /* A range must start with a digit. */ + if (!TOR_ISDIGIT(*s)) { + goto error; + } + /* Note that this wouldn't be safe if we didn't know that eventually, * we'd hit a NUL */ low = (uint32_t) tor_parse_ulong(s, 10, 0, UINT32_MAX, &ok, &next); @@ -138,7 +143,11 @@ parse_version_range(const char *s, const char *end_of_range, if (*next != '-') goto error; s = next+1; + /* ibid */ + if (!TOR_ISDIGIT(*s)) { + goto error; + } high = (uint32_t) tor_parse_ulong(s, 10, 0, UINT32_MAX, &ok, &next); if (!ok) goto error; diff --git a/src/test/test_protover.c b/src/test/test_protover.c index 609003a838..4c41b6db6b 100644 --- a/src/test/test_protover.c +++ b/src/test/test_protover.c @@ -151,11 +151,11 @@ test_protover_vote(void *arg) tt_str_op(result, OP_EQ, ""); tor_free(result); - /* This fails in Rust, but not in C */ + /* This fails, since "-0" is not valid. */ smartlist_clear(lst); smartlist_add(lst, (void*) "Faux=-0"); result = protover_compute_vote(lst, 1); - tt_str_op(result, OP_EQ, "Faux=0"); + tt_str_op(result, OP_EQ, ""); tor_free(result); /* Vote large protover lists that are just below the threshold */ @@ -301,6 +301,8 @@ test_protover_vote_roundtrip(void *args) { "Link=1,fred", NULL }, { "Link=1,fred,3", NULL }, { "Link=1,9-8,3", NULL }, + { "Faux=-0", NULL }, + { "Faux=0--0", NULL }, // "These fail at the splitting stage in Rust, but the number parsing // stage in C." { "Faux=-1", NULL }, -- cgit v1.2.3-54-g00ecf From 1fe0bae508120bbf4954de6b590dd0c722a883bc Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 15 Feb 2018 09:05:55 -0500 Subject: Forbid UINT32_MAX as a protocol version The C code and the rust code had different separate integer overflow bugs here. That suggests that we're better off just forbidding this pathological case. Also, add tests for expected behavior on receiving a bad protocol list in a consensus. Fixes another part of 25249. --- changes/bug25249.2 | 3 +++ src/or/protover.c | 8 ++++++-- src/test/test_protover.c | 21 ++++++++++++++++++--- 3 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 changes/bug25249.2 (limited to 'changes') diff --git a/changes/bug25249.2 b/changes/bug25249.2 new file mode 100644 index 0000000000..9058c11071 --- /dev/null +++ b/changes/bug25249.2 @@ -0,0 +1,3 @@ + o Minor bugfixes (spec conformance): + - Forbid UINT32_MAX as a protocol version. Fixes part of bug 25249; + bugfix on 0.2.9.4-alpha. diff --git a/src/or/protover.c b/src/or/protover.c index f32316f8e7..a035b5c83b 100644 --- a/src/or/protover.c +++ b/src/or/protover.c @@ -103,6 +103,9 @@ proto_entry_free(proto_entry_t *entry) tor_free(entry); } +/** The largest possible protocol version. */ +#define MAX_PROTOCOL_VERSION (UINT32_MAX-1) + /** * Given a string s and optional end-of-string pointer * end_of_range, parse the protocol range and store it in @@ -130,7 +133,7 @@ parse_version_range(const char *s, const char *end_of_range, /* Note that this wouldn't be safe if we didn't know that eventually, * we'd hit a NUL */ - low = (uint32_t) tor_parse_ulong(s, 10, 0, UINT32_MAX, &ok, &next); + low = (uint32_t) tor_parse_ulong(s, 10, 0, MAX_PROTOCOL_VERSION, &ok, &next); if (!ok) goto error; if (next > end_of_range) @@ -148,7 +151,8 @@ parse_version_range(const char *s, const char *end_of_range, if (!TOR_ISDIGIT(*s)) { goto error; } - high = (uint32_t) tor_parse_ulong(s, 10, 0, UINT32_MAX, &ok, &next); + high = (uint32_t) tor_parse_ulong(s, 10, 0, + MAX_PROTOCOL_VERSION, &ok, &next); if (!ok) goto error; if (next != end_of_range) diff --git a/src/test/test_protover.c b/src/test/test_protover.c index 4c41b6db6b..8d061c69ca 100644 --- a/src/test/test_protover.c +++ b/src/test/test_protover.c @@ -257,12 +257,27 @@ test_protover_all_supported(void *arg) tt_str_op(msg, OP_EQ, "Sleen=0-2147483648"); tor_free(msg); - /* Rust seems to experience an internal error here */ - tt_assert(! protover_all_supported("Sleen=0-4294967295", &msg)); - tt_str_op(msg, OP_EQ, "Sleen=0-4294967295"); + /* This case is allowed. */ + tt_assert(! protover_all_supported("Sleen=0-4294967294", &msg)); + tt_str_op(msg, OP_EQ, "Sleen=0-4294967294"); tor_free(msg); + /* If we get an unparseable list, we say "yes, that's supported." */ + tor_capture_bugs_(1); + tt_assert(protover_all_supported("Fribble", &msg)); + tt_ptr_op(msg, OP_EQ, NULL); + tor_end_capture_bugs_(); + + /* This case is forbidden. Since it came from a protover_all_supported, + * it can trigger a bug message. */ + tor_capture_bugs_(1); + tt_assert(protover_all_supported("Sleen=0-4294967295", &msg)); + tt_ptr_op(msg, OP_EQ, NULL); + tor_free(msg); + tor_end_capture_bugs_(); + done: + tor_end_capture_bugs_(); tor_free(msg); } -- cgit v1.2.3-54-g00ecf