diff --git a/changes/bug9286 b/changes/bug9286 new file mode 100644 index 0000000000..062a7a03f3 --- /dev/null +++ b/changes/bug9286 @@ -0,0 +1,4 @@ + o Minor bugfixes (parsing): + - Stop accepting milliseconds (or other junk) at the end of + descriptor publication times. Fixes bug 9286; bugfix on + 0.0.2pre25. \ No newline at end of file diff --git a/src/common/util.c b/src/common/util.c index 1de5edc52c..e5dec99707 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -1704,15 +1704,18 @@ format_iso_time_nospace_usec(char *buf, const struct timeval *tv) /** Given an ISO-formatted UTC time value (after the epoch) in cp, * parse it and store its value in *t. Return 0 on success, -1 on - * failure. Ignore extraneous stuff in cp separated by whitespace from - * the end of the time string. */ + * failure. Ignore extraneous stuff in cp after the end of the time + * string, unless strict is set. */ int -parse_iso_time(const char *cp, time_t *t) +parse_iso_time_(const char *cp, time_t *t, int strict) { struct tm st_tm; unsigned int year=0, month=0, day=0, hour=0, minute=0, second=0; - if (tor_sscanf(cp, "%u-%2u-%2u %2u:%2u:%2u", &year, &month, - &day, &hour, &minute, &second) < 6) { + int n_fields; + char extra_char; + n_fields = tor_sscanf(cp, "%u-%2u-%2u %2u:%2u:%2u%c", &year, &month, + &day, &hour, &minute, &second, &extra_char); + if (strict ? (n_fields != 6) : (n_fields < 6)) { char *esc = esc_for_log(cp); log_warn(LD_GENERAL, "ISO time %s was unparseable", esc); tor_free(esc); @@ -1741,6 +1744,16 @@ parse_iso_time(const char *cp, time_t *t) return tor_timegm(&st_tm, t); } +/** Given an ISO-formatted UTC time value (after the epoch) in cp, + * parse it and store its value in *t. Return 0 on success, -1 on + * failure. Reject the string if any characters are present after the time. + */ +int +parse_iso_time(const char *cp, time_t *t) +{ + return parse_iso_time_(cp, t, 1); +} + /** Given a date in one of the three formats allowed by HTTP (ugh), * parse it into tm. Return 0 on success, negative on failure. */ int diff --git a/src/common/util.h b/src/common/util.h index a1da53890e..ee40949b61 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -274,6 +274,7 @@ void format_local_iso_time(char *buf, time_t t); void format_iso_time(char *buf, time_t t); void format_iso_time_nospace(char *buf, time_t t); void format_iso_time_nospace_usec(char *buf, const struct timeval *tv); +int parse_iso_time_(const char *cp, time_t *t, int strict); int parse_iso_time(const char *buf, time_t *t); int parse_http_time(const char *buf, struct tm *tm); int format_time_interval(char *out, size_t out_len, long interval); diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index e54ca40a25..0f75118be2 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -411,7 +411,7 @@ rend_desc_v2_is_parsable(rend_encoded_v2_service_descriptor_t *desc) &test_intro_content, &test_intro_size, &test_encoded_size, - &test_next, desc->desc_str); + &test_next, desc->desc_str, 1); rend_service_descriptor_free(test_parsed); tor_free(test_intro_content); return (res >= 0); @@ -946,7 +946,7 @@ rend_cache_store_v2_desc_as_dir(const char *desc) } while (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content, &intro_size, &encoded_size, - &next_desc, current_desc) >= 0) { + &next_desc, current_desc, 1) >= 0) { number_parsed++; /* We don't care about the introduction points. */ tor_free(intro_content); @@ -1091,7 +1091,7 @@ rend_cache_store_v2_desc_as_client(const char *desc, /* Parse the descriptor. */ if (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content, &intro_size, &encoded_size, - &next_desc, desc) < 0) { + &next_desc, desc, 0) < 0) { log_warn(LD_REND, "Could not parse descriptor."); goto err; } diff --git a/src/or/routerparse.c b/src/or/routerparse.c index 39063a97b3..a2bc8fbb93 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -4431,6 +4431,9 @@ sort_version_list(smartlist_t *versions, int remove_duplicates) * to *encoded_size_out, and a pointer to the possibly next * descriptor to *next_out; return 0 for success (including validation) * and -1 for failure. + * + * If as_hsdir is 1, we're parsing this as an HSDir, and we should + * be strict about time formats. */ int rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, @@ -4438,7 +4441,8 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, char **intro_points_encrypted_out, size_t *intro_points_encrypted_size_out, size_t *encoded_size_out, - const char **next_out, const char *desc) + const char **next_out, const char *desc, + int as_hsdir) { rend_service_descriptor_t *result = tor_malloc_zero(sizeof(rend_service_descriptor_t)); @@ -4452,6 +4456,8 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, char public_key_hash[DIGEST_LEN]; char test_desc_id[DIGEST_LEN]; memarea_t *area = NULL; + const int strict_time_fmt = as_hsdir; + tor_assert(desc); /* Check if desc starts correctly. */ if (strncmp(desc, "rendezvous-service-descriptor ", @@ -4546,7 +4552,7 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, * descriptor. */ tok = find_by_keyword(tokens, R_PUBLICATION_TIME); tor_assert(tok->n_args == 1); - if (parse_iso_time(tok->args[0], &result->timestamp) < 0) { + if (parse_iso_time_(tok->args[0], &result->timestamp, strict_time_fmt) < 0) { log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]); goto err; } diff --git a/src/or/routerparse.h b/src/or/routerparse.h index 15fd03b810..18a7d2563c 100644 --- a/src/or/routerparse.h +++ b/src/or/routerparse.h @@ -73,7 +73,8 @@ int rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, char **intro_points_encrypted_out, size_t *intro_points_encrypted_size_out, size_t *encoded_size_out, - const char **next_out, const char *desc); + const char **next_out, const char *desc, + int as_hsdir); int rend_decrypt_introduction_points(char **ipos_decrypted, size_t *ipos_decrypted_size, const char *descriptor_cookie, diff --git a/src/test/test.c b/src/test/test.c index 513ec3c597..de6efaf873 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -696,12 +696,12 @@ test_rend_fns(void *arg) smartlist_get(descs, 0))->desc_id, OP_EQ, computed_desc_id, DIGEST_LEN); tt_assert(rend_parse_v2_service_descriptor(&parsed, parsed_desc_id, - &intro_points_encrypted, - &intro_points_size, - &encoded_size, - &next_desc, - ((rend_encoded_v2_service_descriptor_t *) - smartlist_get(descs, 0))->desc_str) == 0); + &intro_points_encrypted, + &intro_points_size, + &encoded_size, + &next_desc, + ((rend_encoded_v2_service_descriptor_t *) + smartlist_get(descs, 0))->desc_str, 1) == 0); tt_assert(parsed); tt_mem_op(((rend_encoded_v2_service_descriptor_t *) smartlist_get(descs, 0))->desc_id,OP_EQ, parsed_desc_id, DIGEST_LEN); diff --git a/src/test/test_util.c b/src/test/test_util.c index 5459c5b9d4..4891356820 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -589,15 +589,17 @@ test_util_time(void *arg) i = parse_iso_time("2004-8-4 0:48:22", &t_res); tt_int_op(0,OP_EQ, i); tt_int_op(t_res,OP_EQ, (time_t)1091580502UL); - tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-zz 99-99x99 GMT", &t_res)); - tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-32 00:00:00 GMT", &t_res)); - tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-30 24:00:00 GMT", &t_res)); - tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-30 23:60:00 GMT", &t_res)); - tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-30 23:59:62 GMT", &t_res)); - tt_int_op(-1,OP_EQ, parse_iso_time("1969-03-30 23:59:59 GMT", &t_res)); - tt_int_op(-1,OP_EQ, parse_iso_time("2011-00-30 23:59:59 GMT", &t_res)); + tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-zz 99-99x99", &t_res)); + tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-32 00:00:00", &t_res)); + tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-30 24:00:00", &t_res)); + tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-30 23:60:00", &t_res)); + tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-30 23:59:62", &t_res)); + tt_int_op(-1,OP_EQ, parse_iso_time("1969-03-30 23:59:59", &t_res)); + tt_int_op(-1,OP_EQ, parse_iso_time("2011-00-30 23:59:59", &t_res)); tt_int_op(-1,OP_EQ, parse_iso_time("2147483647-08-29 14:00:00", &t_res)); tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-30 23:59", &t_res)); + tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04 00:48:22.100", &t_res)); + tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04 00:48:22XYZ", &t_res)); /* Test tor_gettimeofday */