mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-30 23:53:32 +01:00
sendme: Always pop last SENDME digest from circuit
We must not accumulate digests on the circuit if the other end point is using another SENDME version that is not using those digests like v0. This commit makes it that we always pop the digest regardless of the version. Part of #30428 Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
parent
482c4972b9
commit
5479ffabf8
@ -47,47 +47,46 @@ get_accept_min_version(void)
|
|||||||
SENDME_ACCEPT_MIN_VERSION_MAX);
|
SENDME_ACCEPT_MIN_VERSION_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Pop the first cell digset on the given circuit from the SENDME last digests
|
||||||
|
* list. NULL is returned if the list is uninitialized or empty.
|
||||||
|
*
|
||||||
|
* The caller gets ownership of the returned digest thus is responsible for
|
||||||
|
* freeing the memory. */
|
||||||
|
static uint8_t *
|
||||||
|
pop_first_cell_digest(const circuit_t *circ)
|
||||||
|
{
|
||||||
|
uint8_t *circ_digest;
|
||||||
|
|
||||||
|
tor_assert(circ);
|
||||||
|
|
||||||
|
if (circ->sendme_last_digests == NULL ||
|
||||||
|
smartlist_len(circ->sendme_last_digests) == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
circ_digest = smartlist_get(circ->sendme_last_digests, 0);
|
||||||
|
smartlist_del_keeporder(circ->sendme_last_digests, 0);
|
||||||
|
return circ_digest;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return true iff the given cell digest matches the first digest in the
|
/* Return true iff the given cell digest matches the first digest in the
|
||||||
* circuit sendme list. */
|
* circuit sendme list. */
|
||||||
static bool
|
static bool
|
||||||
v1_digest_matches(const circuit_t *circ, const uint8_t *cell_digest)
|
v1_digest_matches(const uint8_t *circ_digest, const uint8_t *cell_digest)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
tor_assert(circ_digest);
|
||||||
uint8_t *circ_digest = NULL;
|
|
||||||
|
|
||||||
tor_assert(circ);
|
|
||||||
tor_assert(cell_digest);
|
tor_assert(cell_digest);
|
||||||
|
|
||||||
/* We shouldn't have received a SENDME if we have no digests. Log at
|
|
||||||
* protocol warning because it can be tricked by sending many SENDMEs
|
|
||||||
* without prior data cell. */
|
|
||||||
if (circ->sendme_last_digests == NULL ||
|
|
||||||
smartlist_len(circ->sendme_last_digests) == 0) {
|
|
||||||
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
|
||||||
"We received a SENDME but we have no cell digests to match. "
|
|
||||||
"Closing circuit.");
|
|
||||||
goto no_match;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pop the first element that was added (FIFO) and compare it. */
|
|
||||||
circ_digest = smartlist_get(circ->sendme_last_digests, 0);
|
|
||||||
smartlist_del_keeporder(circ->sendme_last_digests, 0);
|
|
||||||
|
|
||||||
/* Compare the digest with the one in the SENDME. This cell is invalid
|
/* Compare the digest with the one in the SENDME. This cell is invalid
|
||||||
* without a perfect match. */
|
* without a perfect match. */
|
||||||
if (tor_memneq(circ_digest, cell_digest, TRUNNEL_SENDME_V1_DIGEST_LEN)) {
|
if (tor_memneq(circ_digest, cell_digest, TRUNNEL_SENDME_V1_DIGEST_LEN)) {
|
||||||
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
||||||
"SENDME v1 cell digest do not match.");
|
"SENDME v1 cell digest do not match.");
|
||||||
goto no_match;
|
return false;
|
||||||
}
|
}
|
||||||
/* Digests matches! */
|
|
||||||
ret = true;
|
|
||||||
|
|
||||||
no_match:
|
/* Digests matches! */
|
||||||
/* This digest was popped from the circuit list. Regardless of what happens,
|
return true;
|
||||||
* we have no more use for it. */
|
|
||||||
tor_free(circ_digest);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true iff the given decoded SENDME version 1 cell is valid and
|
/* Return true iff the given decoded SENDME version 1 cell is valid and
|
||||||
@ -97,13 +96,13 @@ v1_digest_matches(const circuit_t *circ, const uint8_t *cell_digest)
|
|||||||
* cell we saw which tells us that the other side has in fact seen that cell.
|
* cell we saw which tells us that the other side has in fact seen that cell.
|
||||||
* See proposal 289 for more details. */
|
* See proposal 289 for more details. */
|
||||||
static bool
|
static bool
|
||||||
cell_v1_is_valid(const sendme_cell_t *cell, const circuit_t *circ)
|
cell_v1_is_valid(const sendme_cell_t *cell, const uint8_t *circ_digest)
|
||||||
{
|
{
|
||||||
tor_assert(cell);
|
tor_assert(cell);
|
||||||
tor_assert(circ);
|
tor_assert(circ_digest);
|
||||||
|
|
||||||
const uint8_t *cell_digest = sendme_cell_getconstarray_data_v1_digest(cell);
|
const uint8_t *cell_digest = sendme_cell_getconstarray_data_v1_digest(cell);
|
||||||
return v1_digest_matches(circ, cell_digest);
|
return v1_digest_matches(circ_digest, cell_digest);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true iff the given cell version can be handled or if the minimum
|
/* Return true iff the given cell version can be handled or if the minimum
|
||||||
@ -160,6 +159,7 @@ sendme_is_valid(const circuit_t *circ, const uint8_t *cell_payload,
|
|||||||
size_t cell_payload_len)
|
size_t cell_payload_len)
|
||||||
{
|
{
|
||||||
uint8_t cell_version;
|
uint8_t cell_version;
|
||||||
|
uint8_t *circ_digest = NULL;
|
||||||
sendme_cell_t *cell = NULL;
|
sendme_cell_t *cell = NULL;
|
||||||
|
|
||||||
tor_assert(circ);
|
tor_assert(circ);
|
||||||
@ -184,10 +184,24 @@ sendme_is_valid(const circuit_t *circ, const uint8_t *cell_payload,
|
|||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Pop the first element that was added (FIFO). We do that regardless of the
|
||||||
|
* version so we don't accumulate on the circuit if v0 is used by the other
|
||||||
|
* end point. */
|
||||||
|
circ_digest = pop_first_cell_digest(circ);
|
||||||
|
if (circ_digest == NULL) {
|
||||||
|
/* We shouldn't have received a SENDME if we have no digests. Log at
|
||||||
|
* protocol warning because it can be tricked by sending many SENDMEs
|
||||||
|
* without prior data cell. */
|
||||||
|
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
||||||
|
"We received a SENDME but we have no cell digests to match. "
|
||||||
|
"Closing circuit.");
|
||||||
|
goto invalid;
|
||||||
|
}
|
||||||
|
|
||||||
/* Validate depending on the version now. */
|
/* Validate depending on the version now. */
|
||||||
switch (cell_version) {
|
switch (cell_version) {
|
||||||
case 0x01:
|
case 0x01:
|
||||||
if (!cell_v1_is_valid(cell, circ)) {
|
if (!cell_v1_is_valid(cell, circ_digest)) {
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -204,9 +218,11 @@ sendme_is_valid(const circuit_t *circ, const uint8_t *cell_payload,
|
|||||||
|
|
||||||
/* Valid cell. */
|
/* Valid cell. */
|
||||||
sendme_cell_free(cell);
|
sendme_cell_free(cell);
|
||||||
|
tor_free(circ_digest);
|
||||||
return true;
|
return true;
|
||||||
invalid:
|
invalid:
|
||||||
sendme_cell_free(cell);
|
sendme_cell_free(cell);
|
||||||
|
tor_free(circ_digest);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "core/or/circuitbuild.h"
|
#include "core/or/circuitbuild.h"
|
||||||
#include "core/or/circuitlist.h"
|
#include "core/or/circuitlist.h"
|
||||||
#include "core/or/connection_edge.h"
|
#include "core/or/connection_edge.h"
|
||||||
|
#include "core/or/sendme.h"
|
||||||
#include "core/or/relay.h"
|
#include "core/or/relay.h"
|
||||||
#include "test/test.h"
|
#include "test/test.h"
|
||||||
#include "test/log_test_helpers.h"
|
#include "test/log_test_helpers.h"
|
||||||
@ -813,6 +814,10 @@ test_circbw_relay(void *arg)
|
|||||||
|
|
||||||
/* Sendme on circuit with non-full window: counted */
|
/* Sendme on circuit with non-full window: counted */
|
||||||
PACK_CELL(0, RELAY_COMMAND_SENDME, "");
|
PACK_CELL(0, RELAY_COMMAND_SENDME, "");
|
||||||
|
/* Recording a cell, the window is updated after decryption so off by one in
|
||||||
|
* order to record and then we process it with the proper window. */
|
||||||
|
circ->cpath->package_window = 901;
|
||||||
|
sendme_record_cell_digest_on_circ(TO_CIRCUIT(circ), circ->cpath);
|
||||||
circ->cpath->package_window = 900;
|
circ->cpath->package_window = 900;
|
||||||
connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
|
connection_edge_process_relay_cell(&cell, TO_CIRCUIT(circ), edgeconn,
|
||||||
circ->cpath);
|
circ->cpath);
|
||||||
|
@ -143,11 +143,13 @@ test_v1_build_cell(void *arg)
|
|||||||
|
|
||||||
or_circ = or_circuit_new(1, NULL);
|
or_circ = or_circuit_new(1, NULL);
|
||||||
circ = TO_CIRCUIT(or_circ);
|
circ = TO_CIRCUIT(or_circ);
|
||||||
|
circ->sendme_last_digests = smartlist_new();
|
||||||
|
|
||||||
cell_digest = crypto_digest_new();
|
cell_digest = crypto_digest_new();
|
||||||
tt_assert(cell_digest);
|
tt_assert(cell_digest);
|
||||||
crypto_digest_add_bytes(cell_digest, "AAAAAAAAAAAAAAAAAAAA", 20);
|
crypto_digest_add_bytes(cell_digest, "AAAAAAAAAAAAAAAAAAAA", 20);
|
||||||
crypto_digest_get_digest(cell_digest, (char *) digest, sizeof(digest));
|
crypto_digest_get_digest(cell_digest, (char *) digest, sizeof(digest));
|
||||||
|
smartlist_add(circ->sendme_last_digests, tor_memdup(digest, sizeof(digest)));
|
||||||
|
|
||||||
/* SENDME v1 payload is 3 bytes + 20 bytes digest. See spec. */
|
/* SENDME v1 payload is 3 bytes + 20 bytes digest. See spec. */
|
||||||
ret = build_cell_payload_v1(digest, payload);
|
ret = build_cell_payload_v1(digest, payload);
|
||||||
@ -157,6 +159,8 @@ test_v1_build_cell(void *arg)
|
|||||||
|
|
||||||
/* An empty payload means SENDME version 0 thus valid. */
|
/* An empty payload means SENDME version 0 thus valid. */
|
||||||
tt_int_op(sendme_is_valid(circ, payload, 0), OP_EQ, true);
|
tt_int_op(sendme_is_valid(circ, payload, 0), OP_EQ, true);
|
||||||
|
/* Current phoney digest should have been popped. */
|
||||||
|
tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0);
|
||||||
|
|
||||||
/* An unparseable cell means invalid. */
|
/* An unparseable cell means invalid. */
|
||||||
setup_full_capture_of_logs(LOG_INFO);
|
setup_full_capture_of_logs(LOG_INFO);
|
||||||
|
Loading…
Reference in New Issue
Block a user