Browse Source

backport candidate:
If a directory server runs out of space in the connection table
as it's processing a begin_dir request, it will free the exit stream
but leave it attached to the circuit, leading to unpredictable
behavior. (Reported by seeess, fixes bug 425.)


svn:r10154

Roger Dingledine 18 years ago
parent
commit
5ffabd4de4
2 changed files with 21 additions and 11 deletions
  1. 8 2
      ChangeLog
  2. 13 9
      src/or/connection_edge.c

+ 8 - 2
ChangeLog

@@ -29,6 +29,12 @@ Changes in version 0.2.0.1-alpha - 2007-??-??
       in the network. Implements proposal 107, suggested by Kevin Bauer
       and Damon McCoy.
 
+  o Crash fixes:
+    - If a directory server runs out of space in the connection table
+      as it's processing a begin_dir request, it will free the exit stream
+      but leave it attached to the circuit, leading to unpredictable
+      behavior. (Reported by seeess, fixes bug 425.)
+
   o Minor fixes (resource management):
     - Count the number of open sockets separately from the number of active
       connection_t objects.  This will let us avoid underusing our
@@ -40,8 +46,8 @@ Changes in version 0.2.0.1-alpha - 2007-??-??
       the server), and avoids the nasty Windows socketpair() workaround.
     - Keep unused 4k and 16k buffers on free lists, rather than wasting 8k
       for every single inactive connection_t.
-    - Free items from the 4/16k-buffer free lists when they haven't been used
-      for a while.
+    - Free items from the 4k/16k-buffer free lists when they haven't been
+      used for a while.
 
   o Minor features (build):
     - Make autoconf search for libevent, openssl, and zlib consistently.

+ 13 - 9
src/or/connection_edge.c

@@ -29,7 +29,8 @@ static smartlist_t *redirect_exit_list = NULL;
 
 static int connection_ap_handshake_process_socks(edge_connection_t *conn);
 static int connection_ap_process_natd(edge_connection_t *conn);
-static int connection_exit_connect_dir(edge_connection_t *exit_conn);
+static int connection_exit_connect_dir(edge_connection_t *exit_conn,
+                                       or_circuit_t *circ);
 static int hostname_is_noconnect_address(const char *address);
 
 /** An AP stream has failed/finished. If it hasn't already sent back
@@ -2218,18 +2219,17 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
     connection_free(TO_CONN(n_stream));
     return 0;
   }
-  log_debug(LD_EXIT,"about to start the dns_resolve().");
+
+  n_stream->on_circuit = circ;
 
   if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
-    if (or_circ && or_circ->p_conn && or_circ->p_conn->_base.addr)
+    tor_assert(or_circ);
+    if (or_circ->p_conn && or_circ->p_conn->_base.addr)
       n_stream->_base.addr = or_circ->p_conn->_base.addr;
-    n_stream->next_stream = TO_OR_CIRCUIT(circ)->n_streams;
-    n_stream->on_circuit = circ;
-    TO_OR_CIRCUIT(circ)->n_streams = n_stream;
-    return connection_exit_connect_dir(n_stream);
+    return connection_exit_connect_dir(n_stream, or_circ);
   }
 
-  n_stream->on_circuit = circ;
+  log_debug(LD_EXIT,"about to start the dns_resolve().");
 
   /* send it off to the gethostbyname farm */
   switch (dns_resolve(n_stream)) {
@@ -2399,7 +2399,8 @@ connection_exit_connect(edge_connection_t *edge_conn)
  * DOCDOC no longer uses socketpair
  */
 static int
-connection_exit_connect_dir(edge_connection_t *exit_conn)
+connection_exit_connect_dir(edge_connection_t *exit_conn,
+                            or_circuit_t *circ)
 {
   dir_connection_t *dir_conn = NULL;
 
@@ -2425,6 +2426,9 @@ connection_exit_connect_dir(edge_connection_t *exit_conn)
     return 0;
   }
 
+  exit_conn->next_stream = circ->n_streams;
+  circ->n_streams = exit_conn;
+
   if (connection_add(TO_CONN(dir_conn))<0) {
     connection_edge_end(exit_conn, END_STREAM_REASON_RESOURCELIMIT);
     connection_close_immediate(TO_CONN(exit_conn));