]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
TROVE-2021-003: Check layer_hint before half-closed end and resolve cells
authorDavid Goulet <dgoulet@torproject.org>
Thu, 3 Jun 2021 13:33:21 +0000 (09:33 -0400)
committerNick Mathewson <nickm@torproject.org>
Thu, 10 Jun 2021 12:50:05 +0000 (08:50 -0400)
This issue was reported by Jann Horn part of Google's Project Zero.

Jann's one-sentence summary: entry/middle relays can spoof RELAY_END cells on
half-closed streams, which can lead to stream confusion between OP and
exit.

Fixes #40389

changes/ticket40389 [new file with mode: 0644]
src/core/or/relay.c

diff --git a/changes/ticket40389 b/changes/ticket40389
new file mode 100644 (file)
index 0000000..7dcf65b
--- /dev/null
@@ -0,0 +1,3 @@
+  o Major bugfixes (relay, TROVE):
+    - Don't allow entry or middle relays to spoof RELAY_END or RELAY_RESOLVED
+      cell on half-closed streams. Fixes bug 40389; bugfix on 0.3.5.1-alpha.
index f5fc1cfbb3967f2f44a7e9fb62a2e029be05ef23..00353f47a9d377963d81339aa323b861886a6c3d 100644 (file)
@@ -1428,6 +1428,25 @@ connection_edge_process_relay_cell_not_open(
 //  return -1;
 }
 
+/**
+ * Return true iff our decryption layer_hint is from the last hop
+ * in a circuit.
+ */
+static bool
+relay_crypt_from_last_hop(origin_circuit_t *circ, crypt_path_t *layer_hint)
+{
+  tor_assert(circ);
+  tor_assert(layer_hint);
+  tor_assert(circ->cpath);
+
+  if (layer_hint != circ->cpath->prev) {
+    log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
+           "Got unexpected relay data from intermediate hop");
+    return false;
+  }
+  return true;
+}
+
 /** An incoming relay cell has arrived on circuit <b>circ</b>. If
  * <b>conn</b> is NULL this is a control cell, else <b>cell</b> is
  * destined for <b>conn</b>.
@@ -1616,7 +1635,8 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
       if (!conn) {
         if (CIRCUIT_IS_ORIGIN(circ)) {
           origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
-          if (connection_half_edge_is_valid_end(ocirc->half_streams,
+          if (relay_crypt_from_last_hop(ocirc, layer_hint) &&
+              connection_half_edge_is_valid_end(ocirc->half_streams,
                                                 rh.stream_id)) {
 
             circuit_read_valid_data(ocirc, rh.length);
@@ -1918,7 +1938,8 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
 
       if (CIRCUIT_IS_ORIGIN(circ)) {
         origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
-        if (connection_half_edge_is_valid_resolved(ocirc->half_streams,
+        if (relay_crypt_from_last_hop(ocirc, layer_hint) &&
+            connection_half_edge_is_valid_resolved(ocirc->half_streams,
                                                     rh.stream_id)) {
           circuit_read_valid_data(ocirc, rh.length);
           log_info(domain,