Avoid free()ing from an mmap on corrupted microdesc cache

The 'body' field of a microdesc_t holds a strdup()'d value if the
microdesc's saved_location field is SAVED_IN_JOURNAL or
SAVED_NOWHERE, and holds a pointer to the middle of an mmap if the
microdesc is SAVED_IN_CACHE.  But we weren't setting that field
until a while after we parsed the microdescriptor, which left an
interval where microdesc_free() would try to free() the middle of
the mmap().

This patch also includes a regression test.

This is a fix for #10409; bugfix on 0.2.2.6-alpha.
This commit is contained in:
Nick Mathewson
2013-12-16 13:00:15 -05:00
parent 9e90707602
commit d8cfa2ef4e
6 changed files with 62 additions and 7 deletions
+10 -3
View File
@@ -4355,12 +4355,17 @@ find_start_of_next_microdesc(const char *s, const char *eos)
/** Parse as many microdescriptors as are found from the string starting at
* <b>s</b> and ending at <b>eos</b>. If allow_annotations is set, read any
* annotations we recognize and ignore ones we don't. If <b>copy_body</b> is
* true, then strdup the bodies of the microdescriptors. Return all newly
* annotations we recognize and ignore ones we don't.
*
* If <b>saved_location</b> isn't SAVED_IN_CACHE, make a local copy of each
* descriptor in the body field of each microdesc_t.
*
* Return all newly
* parsed microdescriptors in a newly allocated smartlist_t. */
smartlist_t *
microdescs_parse_from_string(const char *s, const char *eos,
int allow_annotations, int copy_body)
int allow_annotations,
saved_location_t where)
{
smartlist_t *tokens;
smartlist_t *result;
@@ -4369,6 +4374,7 @@ microdescs_parse_from_string(const char *s, const char *eos,
const char *start = s;
const char *start_of_next_microdesc;
int flags = allow_annotations ? TS_ANNOTATIONS_OK : 0;
const int copy_body = (where != SAVED_IN_CACHE);
directory_token_t *tok;
@@ -4398,6 +4404,7 @@ microdescs_parse_from_string(const char *s, const char *eos,
tor_assert(cp);
md->bodylen = start_of_next_microdesc - cp;
md->saved_location = where;
if (copy_body)
md->body = tor_strndup(cp, md->bodylen);
else