mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-30 23:53:32 +01:00
Merge branch 'bug1653'
This commit is contained in:
commit
aa42f941dc
8
changes/bug1653
Normal file
8
changes/bug1653
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
o Major bugfixes:
|
||||||
|
- When the exit relay gets a circuit-level sendme cell, it started
|
||||||
|
reading on the exit streams, even if had 500 cells queued in our
|
||||||
|
circuit queue already, so our circuit queue just grew and grew
|
||||||
|
in some cases. We fix this by not re-enabling reading on SENDME
|
||||||
|
while the cell queue is blocked. Fixes bug 1653. Bugfix on
|
||||||
|
0.2.0.1-alpha. Detected by Mashael AlSabah. Original patch by
|
||||||
|
"yetonetime".
|
8
changes/detect-full-queues
Normal file
8
changes/detect-full-queues
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
o Major bugfixes:
|
||||||
|
- Newly created streams were allowed to read cells onto circuits,
|
||||||
|
even if the circuit's cell queue was blocked and waiting to drain.
|
||||||
|
This created potential unfairness, as older streams would be
|
||||||
|
blocked, but newer streams would gladly fill the queue completely.
|
||||||
|
We add code to detect this situation and prevent any stream from
|
||||||
|
getting more than one free cell. Bugfix on 0.2.0.1-alpha.
|
||||||
|
Possible partial fix for bug 1298.
|
@ -1752,7 +1752,7 @@ circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type,
|
|||||||
cell.circ_id = circ->n_circ_id;
|
cell.circ_id = circ->n_circ_id;
|
||||||
|
|
||||||
memcpy(cell.payload, payload, ONIONSKIN_CHALLENGE_LEN);
|
memcpy(cell.payload, payload, ONIONSKIN_CHALLENGE_LEN);
|
||||||
append_cell_to_circuit_queue(circ, circ->n_conn, &cell, CELL_DIRECTION_OUT);
|
append_cell_to_circuit_queue(circ, circ->n_conn, &cell, CELL_DIRECTION_OUT, 0);
|
||||||
|
|
||||||
if (CIRCUIT_IS_ORIGIN(circ)) {
|
if (CIRCUIT_IS_ORIGIN(circ)) {
|
||||||
/* mark it so it gets better rate limiting treatment. */
|
/* mark it so it gets better rate limiting treatment. */
|
||||||
@ -2329,7 +2329,7 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload,
|
|||||||
circ->is_first_hop = (cell_type == CELL_CREATED_FAST);
|
circ->is_first_hop = (cell_type == CELL_CREATED_FAST);
|
||||||
|
|
||||||
append_cell_to_circuit_queue(TO_CIRCUIT(circ),
|
append_cell_to_circuit_queue(TO_CIRCUIT(circ),
|
||||||
circ->p_conn, &cell, CELL_DIRECTION_IN);
|
circ->p_conn, &cell, CELL_DIRECTION_IN, 0);
|
||||||
log_debug(LD_CIRC,"Finished sending 'created' cell.");
|
log_debug(LD_CIRC,"Finished sending 'created' cell.");
|
||||||
|
|
||||||
if (!is_local_addr(&circ->p_conn->_base.addr) &&
|
if (!is_local_addr(&circ->p_conn->_base.addr) &&
|
||||||
|
@ -52,6 +52,7 @@ circuit_resume_edge_reading_helper(edge_connection_t *conn,
|
|||||||
crypt_path_t *layer_hint);
|
crypt_path_t *layer_hint);
|
||||||
static int
|
static int
|
||||||
circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint);
|
circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint);
|
||||||
|
static int circuit_queue_streams_are_blocked(circuit_t *circ);
|
||||||
|
|
||||||
/** Cache the current hi-res time; the cache gets reset when libevent
|
/** Cache the current hi-res time; the cache gets reset when libevent
|
||||||
* calls us. */
|
* calls us. */
|
||||||
@ -268,7 +269,7 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
|
|||||||
* we might kill the circ before we relay
|
* we might kill the circ before we relay
|
||||||
* the cells. */
|
* the cells. */
|
||||||
|
|
||||||
append_cell_to_circuit_queue(circ, or_conn, cell, cell_direction);
|
append_cell_to_circuit_queue(circ, or_conn, cell, cell_direction, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,7 +366,7 @@ relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction,
|
|||||||
static int
|
static int
|
||||||
circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
|
circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
|
||||||
cell_direction_t cell_direction,
|
cell_direction_t cell_direction,
|
||||||
crypt_path_t *layer_hint)
|
crypt_path_t *layer_hint, uint16_t on_stream)
|
||||||
{
|
{
|
||||||
or_connection_t *conn; /* where to send the cell */
|
or_connection_t *conn; /* where to send the cell */
|
||||||
|
|
||||||
@ -409,7 +410,7 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
|
|||||||
}
|
}
|
||||||
++stats_n_relay_cells_relayed;
|
++stats_n_relay_cells_relayed;
|
||||||
|
|
||||||
append_cell_to_circuit_queue(circ, conn, cell, cell_direction);
|
append_cell_to_circuit_queue(circ, conn, cell, cell_direction, on_stream);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -624,8 +625,8 @@ relay_send_command_from_edge(uint16_t stream_id, circuit_t *circ,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (circuit_package_relay_cell(&cell, circ, cell_direction, cpath_layer)
|
if (circuit_package_relay_cell(&cell, circ, cell_direction, cpath_layer,
|
||||||
< 0) {
|
stream_id) < 0) {
|
||||||
log_warn(LD_BUG,"circuit_package_relay_cell failed. Closing.");
|
log_warn(LD_BUG,"circuit_package_relay_cell failed. Closing.");
|
||||||
circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
|
circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
|
||||||
return -1;
|
return -1;
|
||||||
@ -1236,6 +1237,10 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
|
|||||||
conn->package_window += STREAMWINDOW_INCREMENT;
|
conn->package_window += STREAMWINDOW_INCREMENT;
|
||||||
log_debug(domain,"stream-level sendme, packagewindow now %d.",
|
log_debug(domain,"stream-level sendme, packagewindow now %d.",
|
||||||
conn->package_window);
|
conn->package_window);
|
||||||
|
if (circuit_queue_streams_are_blocked(circ)) {
|
||||||
|
/* Still waiting for queue to flush; don't touch conn */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
connection_start_reading(TO_CONN(conn));
|
connection_start_reading(TO_CONN(conn));
|
||||||
/* handle whatever might still be on the inbuf */
|
/* handle whatever might still be on the inbuf */
|
||||||
if (connection_edge_package_raw_inbuf(conn, 1) < 0) {
|
if (connection_edge_package_raw_inbuf(conn, 1) < 0) {
|
||||||
@ -1436,7 +1441,10 @@ connection_edge_consider_sending_sendme(edge_connection_t *conn)
|
|||||||
static void
|
static void
|
||||||
circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint)
|
circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint)
|
||||||
{
|
{
|
||||||
|
if (circuit_queue_streams_are_blocked(circ)) {
|
||||||
|
log_debug(layer_hint?LD_APP:LD_EXIT,"Too big queue, no resuming");
|
||||||
|
return;
|
||||||
|
}
|
||||||
log_debug(layer_hint?LD_APP:LD_EXIT,"resuming");
|
log_debug(layer_hint?LD_APP:LD_EXIT,"resuming");
|
||||||
|
|
||||||
if (CIRCUIT_IS_ORIGIN(circ))
|
if (CIRCUIT_IS_ORIGIN(circ))
|
||||||
@ -2092,12 +2100,19 @@ connection_or_unlink_all_active_circs(or_connection_t *orconn)
|
|||||||
|
|
||||||
/** Block (if <b>block</b> is true) or unblock (if <b>block</b> is false)
|
/** Block (if <b>block</b> is true) or unblock (if <b>block</b> is false)
|
||||||
* every edge connection that is using <b>circ</b> to write to <b>orconn</b>,
|
* every edge connection that is using <b>circ</b> to write to <b>orconn</b>,
|
||||||
* and start or stop reading as appropriate. */
|
* and start or stop reading as appropriate.
|
||||||
static void
|
*
|
||||||
|
* If <b>stream_id</b> is nonzero, block only the edge connection whose
|
||||||
|
* stream_id matches it.
|
||||||
|
*
|
||||||
|
* Returns the number of streams whose status we changed.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
set_streams_blocked_on_circ(circuit_t *circ, or_connection_t *orconn,
|
set_streams_blocked_on_circ(circuit_t *circ, or_connection_t *orconn,
|
||||||
int block)
|
int block, uint16_t stream_id)
|
||||||
{
|
{
|
||||||
edge_connection_t *edge = NULL;
|
edge_connection_t *edge = NULL;
|
||||||
|
int n = 0;
|
||||||
if (circ->n_conn == orconn) {
|
if (circ->n_conn == orconn) {
|
||||||
circ->streams_blocked_on_n_conn = block;
|
circ->streams_blocked_on_n_conn = block;
|
||||||
if (CIRCUIT_IS_ORIGIN(circ))
|
if (CIRCUIT_IS_ORIGIN(circ))
|
||||||
@ -2110,7 +2125,13 @@ set_streams_blocked_on_circ(circuit_t *circ, or_connection_t *orconn,
|
|||||||
|
|
||||||
for (; edge; edge = edge->next_stream) {
|
for (; edge; edge = edge->next_stream) {
|
||||||
connection_t *conn = TO_CONN(edge);
|
connection_t *conn = TO_CONN(edge);
|
||||||
edge->edge_blocked_on_circ = block;
|
if (stream_id && edge->stream_id != stream_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (edge->edge_blocked_on_circ != block) {
|
||||||
|
++n;
|
||||||
|
edge->edge_blocked_on_circ = block;
|
||||||
|
}
|
||||||
|
|
||||||
if (!conn->read_event) {
|
if (!conn->read_event) {
|
||||||
/* This connection is a placeholder for something; probably a DNS
|
/* This connection is a placeholder for something; probably a DNS
|
||||||
@ -2127,6 +2148,8 @@ set_streams_blocked_on_circ(circuit_t *circ, or_connection_t *orconn,
|
|||||||
connection_start_reading(conn);
|
connection_start_reading(conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Pull as many cells as possible (but no more than <b>max</b>) from the
|
/** Pull as many cells as possible (but no more than <b>max</b>) from the
|
||||||
@ -2252,7 +2275,7 @@ connection_or_flush_from_first_active_circuit(or_connection_t *conn, int max,
|
|||||||
/* Is the cell queue low enough to unblock all the streams that are waiting
|
/* Is the cell queue low enough to unblock all the streams that are waiting
|
||||||
* to write to this circuit? */
|
* to write to this circuit? */
|
||||||
if (streams_blocked && queue->n <= CELL_QUEUE_LOWWATER_SIZE)
|
if (streams_blocked && queue->n <= CELL_QUEUE_LOWWATER_SIZE)
|
||||||
set_streams_blocked_on_circ(circ, conn, 0); /* unblock streams */
|
set_streams_blocked_on_circ(circ, conn, 0, 0); /* unblock streams */
|
||||||
|
|
||||||
/* Did we just run out of cells on this circuit's queue? */
|
/* Did we just run out of cells on this circuit's queue? */
|
||||||
if (queue->n == 0) {
|
if (queue->n == 0) {
|
||||||
@ -2269,7 +2292,8 @@ connection_or_flush_from_first_active_circuit(or_connection_t *conn, int max,
|
|||||||
* transmitting in <b>direction</b>. */
|
* transmitting in <b>direction</b>. */
|
||||||
void
|
void
|
||||||
append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
|
append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
|
||||||
cell_t *cell, cell_direction_t direction)
|
cell_t *cell, cell_direction_t direction,
|
||||||
|
uint16_t fromstream)
|
||||||
{
|
{
|
||||||
cell_queue_t *queue;
|
cell_queue_t *queue;
|
||||||
int streams_blocked;
|
int streams_blocked;
|
||||||
@ -2291,7 +2315,12 @@ append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
|
|||||||
/* If we have too many cells on the circuit, we should stop reading from
|
/* If we have too many cells on the circuit, we should stop reading from
|
||||||
* the edge streams for a while. */
|
* the edge streams for a while. */
|
||||||
if (!streams_blocked && queue->n >= CELL_QUEUE_HIGHWATER_SIZE)
|
if (!streams_blocked && queue->n >= CELL_QUEUE_HIGHWATER_SIZE)
|
||||||
set_streams_blocked_on_circ(circ, orconn, 1); /* block streams */
|
set_streams_blocked_on_circ(circ, orconn, 1, 0); /* block streams */
|
||||||
|
|
||||||
|
if (streams_blocked && fromstream) {
|
||||||
|
/* This edge connection is apparently not blocked; block it. */
|
||||||
|
set_streams_blocked_on_circ(circ, orconn, 1, fromstream);
|
||||||
|
}
|
||||||
|
|
||||||
if (queue->n == 1) {
|
if (queue->n == 1) {
|
||||||
/* This was the first cell added to the queue. We need to make this
|
/* This was the first cell added to the queue. We need to make this
|
||||||
@ -2405,3 +2434,15 @@ assert_active_circuits_ok(or_connection_t *orconn)
|
|||||||
tor_assert(n == smartlist_len(orconn->active_circuit_pqueue));
|
tor_assert(n == smartlist_len(orconn->active_circuit_pqueue));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return 1 if we shouldn't restart reading on this circuit, even if
|
||||||
|
* we get a SENDME. Else return 0.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
circuit_queue_streams_are_blocked(circuit_t *circ)
|
||||||
|
{
|
||||||
|
if (CIRCUIT_IS_ORIGIN(circ)) {
|
||||||
|
return circ->streams_blocked_on_n_conn;
|
||||||
|
} else {
|
||||||
|
return circ->streams_blocked_on_p_conn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -45,7 +45,8 @@ void cell_queue_append(cell_queue_t *queue, packed_cell_t *cell);
|
|||||||
void cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell);
|
void cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell);
|
||||||
|
|
||||||
void append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
|
void append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
|
||||||
cell_t *cell, cell_direction_t direction);
|
cell_t *cell, cell_direction_t direction,
|
||||||
|
uint16_t fromstream);
|
||||||
void connection_or_unlink_all_active_circs(or_connection_t *conn);
|
void connection_or_unlink_all_active_circs(or_connection_t *conn);
|
||||||
int connection_or_flush_from_first_active_circuit(or_connection_t *conn,
|
int connection_or_flush_from_first_active_circuit(or_connection_t *conn,
|
||||||
int max, time_t now);
|
int max, time_t now);
|
||||||
|
Loading…
Reference in New Issue
Block a user