]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Fix bug 9082: avoid leak when freeing destroy cell queues
authorNick Mathewson <nickm@torproject.org>
Mon, 17 Jun 2013 15:30:56 +0000 (11:30 -0400)
committerNick Mathewson <nickm@torproject.org>
Mon, 17 Jun 2013 15:30:56 +0000 (11:30 -0400)
In my #7912 fix, there wasn't any code to remove entries from the
(channel, circuit ID)->circuit map corresponding to queued but un-sent
DESTROYs.

Spotted by skruffy. Fixes bug 9082; bug not in any released Tor.

src/or/channel.c
src/or/channel.h
src/or/circuitmux.c
src/or/circuitmux.h

index 33a32102eec83278dcaacb2ecdf91edb24784e20..98c23d91ea500976e2ae083e0504a9dfe24482a7 100644 (file)
@@ -803,6 +803,7 @@ channel_free(channel_t *chan)
   /* Get rid of cmux */
   if (chan->cmux) {
     circuitmux_detach_all_circuits(chan->cmux);
+    circuitmux_mark_destroyed_circids_usable(chan->cmux, chan);
     circuitmux_free(chan->cmux);
     chan->cmux = NULL;
   }
@@ -2616,6 +2617,29 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell)
   }
 }
 
+/** If <b>packed_cell</b> on <b>chan</b> is a destroy cell, then set
+ * *<b>circid_out</b> to its circuit ID, and return true.  Otherwise, return
+ * false. */
+/* XXXX Move this function. */
+int
+packed_cell_is_destroy(channel_t *chan,
+                       const packed_cell_t *packed_cell,
+                       circid_t *circid_out)
+{
+  if (chan->wide_circ_ids) {
+    if (packed_cell->body[4] == CELL_DESTROY) {
+      *circid_out = ntohl(get_uint32(packed_cell->body));
+      return 1;
+    }
+  } else {
+    if (packed_cell->body[2] == CELL_DESTROY) {
+      *circid_out = ntohs(get_uint16(packed_cell->body));
+      return 1;
+    }
+  }
+  return 0;
+}
+
 /** DOCDOC */
 static int
 is_destroy_cell(channel_t *chan,
@@ -2636,18 +2660,7 @@ is_destroy_cell(channel_t *chan,
       }
       break;
     case CELL_QUEUE_PACKED:
-      if (chan->wide_circ_ids) {
-        if (q->u.packed.packed_cell->body[4] == CELL_DESTROY) {
-          *circid_out = ntohl(get_uint32(q->u.packed.packed_cell->body));
-          return 1;
-        }
-      } else {
-        if (q->u.packed.packed_cell->body[2] == CELL_DESTROY) {
-          *circid_out = ntohs(get_uint16(q->u.packed.packed_cell->body));
-          return 1;
-        }
-      }
-      break;
+      return packed_cell_is_destroy(chan, q->u.packed.packed_cell, circid_out);
   }
   return 0;
 }
index 0933ec8d3907f703d8579caf971c14d0628d0d36..83d7e900fff3c9618620a2ce916d5f50fdca5967 100644 (file)
@@ -477,5 +477,9 @@ uint64_t channel_count_xmitted(channel_t *chan);
 
 uint64_t channel_listener_count_accepted(channel_listener_t *chan_l);
 
+int packed_cell_is_destroy(channel_t *chan,
+                           const packed_cell_t *packed_cell,
+                           circid_t *circid_out);
+
 #endif
 
index f579c3ead16c6d9a4c7fc69a95b45aaf184fd4d3..c84e0ce09cfc1c573c6071486001b47b61b3397d 100644 (file)
@@ -498,6 +498,31 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux)
   cmux->n_cells = 0;
 }
 
+/** Reclaim all circuit IDs currently marked as unusable on <b>chan</b> because
+ * of pending destroy cells in <b>cmux</b>.
+ *
+ * This function must be called AFTER circuits are unlinked from the (channel,
+ * circuid-id) map with circuit_unlink_all_from_channel(), but before calling
+ * circuitmux_free().
+ */
+void
+circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, channel_t *chan)
+{
+  packed_cell_t *cell;
+  int n_bad = 0;
+  for (cell = cmux->destroy_cell_queue.head; cell; cell = cell->next) {
+    circid_t circid = 0;
+    if (packed_cell_is_destroy(chan, cell, &circid)) {
+      channel_mark_circid_usable(chan, circid);
+    } else {
+      ++n_bad;
+    }
+  }
+  if (n_bad)
+    log_warn(LD_BUG, "%d cell(s) on destroy queue did not look like a "
+             "DESTROY cell.", n_bad);
+}
+
 /**
  * Free a circuitmux_t; the circuits must be detached first with
  * circuitmux_detach_all_circuits().
index 9ff29de70ad344ea317dd2af7d1f8d9afecc5b0e..a6bc415cdda41a2e6e59d787b7e09a5e2c03e6d4 100644 (file)
@@ -137,6 +137,8 @@ void circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
 void circuitmux_append_destroy_cell(channel_t *chan,
                                     circuitmux_t *cmux, circid_t circ_id,
                                     uint8_t reason);
+void circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux,
+                                              channel_t *chan);
 
 #endif /* TOR_CIRCUITMUX_H */