Repair breakage in early-error case of microdesc parsing

When I fixed #11243, I made it so we would take the digest of a
descriptor before tokenizing it, so we could desist from download
attempts if parsing failed.  But when I did that, I didn't remove an
assertion that the descriptor began with "onion-key".  Usually, this
was enforced by "find_start_of_next_microdescriptor", but when
find_start_of_next_microdescriptor returned NULL, the assertion was
triggered.

Fixes bug 16400.  Thanks to torkeln for reporting and
cypherpunks_backup for diagnosing and writing the first fix here.
This commit is contained in:
Nick Mathewson 2015-06-22 13:51:56 -04:00
parent c8cb55659a
commit e0b7598833
3 changed files with 50 additions and 3 deletions

5
changes/bug16400 Normal file
View File

@ -0,0 +1,5 @@
o Major bugfixes:
- Do not crash with an assertion error when parsing certain kinds
of malformed or truncated microdescriptors. Fixes bug 16400;
bugfix on 0.2.6.1-alpha. Found by "torkeln"; fix based on a patch by
"cypherpunks_backup".

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2001 Matej Pfajfar.
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2015, The Tor Project, Inc. */
@ -4165,7 +4165,10 @@ microdescs_parse_from_string(const char *s, const char *eos,
{
const char *cp = tor_memstr(s, start_of_next_microdesc-s,
"onion-key");
tor_assert(cp);
const int no_onion_key = (cp == NULL);
if (no_onion_key) {
cp = s; /* So that we have *some* junk to put in the body */
}
md->bodylen = start_of_next_microdesc - cp;
md->saved_location = where;
@ -4174,8 +4177,13 @@ microdescs_parse_from_string(const char *s, const char *eos,
else
md->body = (char*)cp;
md->off = cp - start;
crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256);
if (no_onion_key) {
log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Malformed or truncated descriptor");
goto next;
}
}
crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256);
if (tokenize_string(area, s, start_of_next_microdesc, tokens,
microdesc_token_table, flags)) {

View File

@ -713,12 +713,46 @@ test_md_reject_cache(void *arg)
tor_free(mock_ns_val);
}
static void
test_md_corrupt_desc(void *arg)
{
char *cp = NULL;
smartlist_t *sl = NULL;
(void) arg;
sl = microdescs_add_to_cache(get_microdesc_cache(),
"@last-listed 2015-06-22 10:00:00\n"
"onion-k\n",
NULL, SAVED_IN_JOURNAL, 0, time(NULL), NULL);
tt_int_op(smartlist_len(sl), ==, 0);
smartlist_free(sl);
sl = microdescs_add_to_cache(get_microdesc_cache(),
"@last-listed 2015-06-22 10:00:00\n"
"wiggly\n",
NULL, SAVED_IN_JOURNAL, 0, time(NULL), NULL);
tt_int_op(smartlist_len(sl), ==, 0);
smartlist_free(sl);
tor_asprintf(&cp, "%s\n%s", test_md1, "@foobar\nonion-wobble\n");
sl = microdescs_add_to_cache(get_microdesc_cache(),
cp, cp+strlen(cp),
SAVED_IN_JOURNAL, 0, time(NULL), NULL);
tt_int_op(smartlist_len(sl), ==, 0);
smartlist_free(sl);
done:
tor_free(cp);
}
struct testcase_t microdesc_tests[] = {
{ "cache", test_md_cache, TT_FORK, NULL, NULL },
{ "broken_cache", test_md_cache_broken, TT_FORK, NULL, NULL },
{ "generate", test_md_generate, 0, NULL, NULL },
{ "parse", test_md_parse, 0, NULL, NULL },
{ "reject_cache", test_md_reject_cache, TT_FORK, NULL, NULL },
{ "corrupt_desc", test_md_corrupt_desc, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};