aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2014-02-07 10:38:24 -0500
committerNick Mathewson <nickm@torproject.org>2014-02-07 10:38:24 -0500
commit372adfa09a143490dfc058a6e2db78ca27ef9399 (patch)
treea01dd55e84961d85b1067a6d1c22cd1764ccb0b6
parent5990edd1952361faca4619728b50587061d81be7 (diff)
parenta7e946596d6da9aca80456141b7fddbc198c217c (diff)
downloadtor-372adfa09a143490dfc058a6e2db78ca27ef9399.tar
tor-372adfa09a143490dfc058a6e2db78ca27ef9399.tar.gz
Merge remote-tracking branch 'origin/maint-0.2.4'
-rw-r--r--changes/bug96025
-rw-r--r--src/or/channeltls.c193
-rw-r--r--src/or/connection.c16
-rw-r--r--src/or/connection_or.c5
4 files changed, 150 insertions, 69 deletions
diff --git a/changes/bug9602 b/changes/bug9602
new file mode 100644
index 000000000..2dc13c4c0
--- /dev/null
+++ b/changes/bug9602
@@ -0,0 +1,5 @@
+ o Bugfixes
+ - Null out orconn->chan->conn when closing orconn in case orconn is freed
+ before channel_run_cleanup() gets to orconn->chan, and handle the null
+ conn edge case correctly in channel_tls_t methods. Fixes bug #9602;
+ bugfix on 0.2.4.4-alpha.
diff --git a/src/or/channeltls.c b/src/or/channeltls.c
index 9a290778f..e76bae3da 100644
--- a/src/or/channeltls.c
+++ b/src/or/channeltls.c
@@ -368,7 +368,7 @@ channel_tls_describe_transport_method(channel_t *chan)
tor_assert(chan);
- tlschan = BASE_CHAN_TO_TLS(chan);
+ tlschan = BASE_CHAN_TO_TLS(chan);
if (tlschan->conn) {
id = TO_CONN(tlschan->conn)->global_identifier;
@@ -397,15 +397,18 @@ channel_tls_describe_transport_method(channel_t *chan)
static int
channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out)
{
+ int rv = 0;
channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
tor_assert(tlschan);
tor_assert(addr_out);
- tor_assert(tlschan->conn);
- tor_addr_copy(addr_out, &(TO_CONN(tlschan->conn)->addr));
+ if (tlschan->conn) {
+ tor_addr_copy(addr_out, &(TO_CONN(tlschan->conn)->addr));
+ rv = 1;
+ } else tor_addr_make_unspec(addr_out);
- return 1;
+ return rv;
}
/**
@@ -453,41 +456,43 @@ channel_tls_get_remote_descr_method(channel_t *chan, int flags)
char *addr_str;
tor_assert(tlschan);
- tor_assert(tlschan->conn);
- conn = TO_CONN(tlschan->conn);
-
- switch (flags) {
- case 0:
- /* Canonical address with port*/
- tor_snprintf(buf, MAX_DESCR_LEN + 1,
- "%s:%u", conn->address, conn->port);
- answer = buf;
- break;
- case GRD_FLAG_ORIGINAL:
- /* Actual address with port */
- addr_str = tor_dup_addr(&(tlschan->conn->real_addr));
- tor_snprintf(buf, MAX_DESCR_LEN + 1,
- "%s:%u", addr_str, conn->port);
- tor_free(addr_str);
- answer = buf;
- break;
- case GRD_FLAG_ADDR_ONLY:
- /* Canonical address, no port */
- strlcpy(buf, conn->address, sizeof(buf));
- answer = buf;
- break;
- case GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY:
- /* Actual address, no port */
- addr_str = tor_dup_addr(&(tlschan->conn->real_addr));
- strlcpy(buf, addr_str, sizeof(buf));
- tor_free(addr_str);
- answer = buf;
- break;
-
- default:
- /* Something's broken in channel.c */
- tor_assert(1);
+ if (tlschan->conn) {
+ conn = TO_CONN(tlschan->conn);
+ switch (flags) {
+ case 0:
+ /* Canonical address with port*/
+ tor_snprintf(buf, MAX_DESCR_LEN + 1,
+ "%s:%u", conn->address, conn->port);
+ answer = buf;
+ break;
+ case GRD_FLAG_ORIGINAL:
+ /* Actual address with port */
+ addr_str = tor_dup_addr(&(tlschan->conn->real_addr));
+ tor_snprintf(buf, MAX_DESCR_LEN + 1,
+ "%s:%u", addr_str, conn->port);
+ tor_free(addr_str);
+ answer = buf;
+ break;
+ case GRD_FLAG_ADDR_ONLY:
+ /* Canonical address, no port */
+ strlcpy(buf, conn->address, sizeof(buf));
+ answer = buf;
+ break;
+ case GRD_FLAG_ORIGINAL|GRD_FLAG_ADDR_ONLY:
+ /* Actual address, no port */
+ addr_str = tor_dup_addr(&(tlschan->conn->real_addr));
+ strlcpy(buf, addr_str, sizeof(buf));
+ tor_free(addr_str);
+ answer = buf;
+ break;
+ default:
+ /* Something's broken in channel.c */
+ tor_assert(1);
+ }
+ } else {
+ strlcpy(buf, "(No connection)", sizeof(buf));
+ answer = buf;
}
return answer;
@@ -507,9 +512,16 @@ channel_tls_has_queued_writes_method(channel_t *chan)
channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
tor_assert(tlschan);
- tor_assert(tlschan->conn);
+ if (!(tlschan->conn)) {
+ log_info(LD_CHANNEL,
+ "something called has_queued_writes on a tlschan "
+ "(%p with ID " U64_FORMAT " but no conn",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ }
- outbuf_len = connection_get_outbuf_len(TO_CONN(tlschan->conn));
+ outbuf_len = (tlschan->conn != NULL) ?
+ connection_get_outbuf_len(TO_CONN(tlschan->conn)) :
+ 0;
return (outbuf_len > 0);
}
@@ -529,24 +541,26 @@ channel_tls_is_canonical_method(channel_t *chan, int req)
channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
tor_assert(tlschan);
- tor_assert(tlschan->conn);
- switch (req) {
- case 0:
- answer = tlschan->conn->is_canonical;
- break;
- case 1:
- /*
- * Is the is_canonical bit reliable? In protocols version 2 and up
- * we get the canonical address from a NETINFO cell, but in older
- * versions it might be based on an obsolete descriptor.
- */
- answer = (tlschan->conn->link_proto >= 2);
- break;
- default:
- /* This shouldn't happen; channel.c is broken if it does */
- tor_assert(1);
+ if (tlschan->conn) {
+ switch (req) {
+ case 0:
+ answer = tlschan->conn->is_canonical;
+ break;
+ case 1:
+ /*
+ * Is the is_canonical bit reliable? In protocols version 2 and up
+ * we get the canonical address from a NETINFO cell, but in older
+ * versions it might be based on an obsolete descriptor.
+ */
+ answer = (tlschan->conn->link_proto >= 2);
+ break;
+ default:
+ /* This shouldn't happen; channel.c is broken if it does */
+ tor_assert(1);
+ }
}
+ /* else return 0 for tlschan->conn == NULL */
return answer;
}
@@ -567,6 +581,15 @@ channel_tls_matches_extend_info_method(channel_t *chan,
tor_assert(tlschan);
tor_assert(extend_info);
+ /* Never match if we have no conn */
+ if (!(tlschan->conn)) {
+ log_info(LD_CHANNEL,
+ "something called matches_extend_info on a tlschan "
+ "(%p with ID " U64_FORMAT " but no conn",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ return 0;
+ }
+
return (tor_addr_eq(&(extend_info->addr),
&(TO_CONN(tlschan->conn)->addr)) &&
(extend_info->port == TO_CONN(tlschan->conn)->port));
@@ -588,7 +611,15 @@ channel_tls_matches_target_method(channel_t *chan,
tor_assert(tlschan);
tor_assert(target);
- tor_assert(tlschan->conn);
+
+ /* Never match if we have no conn */
+ if (!(tlschan->conn)) {
+ log_info(LD_CHANNEL,
+ "something called matches_target on a tlschan "
+ "(%p with ID " U64_FORMAT " but no conn",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ return 0;
+ }
return tor_addr_eq(&(tlschan->conn->real_addr), target);
}
@@ -604,14 +635,22 @@ static int
channel_tls_write_cell_method(channel_t *chan, cell_t *cell)
{
channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+ int written = 0;
tor_assert(tlschan);
tor_assert(cell);
- tor_assert(tlschan->conn);
- connection_or_write_cell_to_buf(cell, tlschan->conn);
+ if (tlschan->conn) {
+ connection_or_write_cell_to_buf(cell, tlschan->conn);
+ ++written;
+ } else {
+ log_info(LD_CHANNEL,
+ "something called write_cell on a tlschan "
+ "(%p with ID " U64_FORMAT " but no conn",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ }
- return 1;
+ return written;
}
/**
@@ -627,18 +666,26 @@ channel_tls_write_packed_cell_method(channel_t *chan,
{
channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
size_t cell_network_size = get_cell_network_size(chan->wide_circ_ids);
+ int written = 0;
tor_assert(tlschan);
tor_assert(packed_cell);
- tor_assert(tlschan->conn);
- connection_write_to_buf(packed_cell->body, cell_network_size,
- TO_CONN(tlschan->conn));
+ if (tlschan->conn) {
+ connection_write_to_buf(packed_cell->body, cell_network_size,
+ TO_CONN(tlschan->conn));
- /* This is where the cell is finished; used to be done from relay.c */
- packed_cell_free(packed_cell);
+ /* This is where the cell is finished; used to be done from relay.c */
+ packed_cell_free(packed_cell);
+ ++written;
+ } else {
+ log_info(LD_CHANNEL,
+ "something called write_packed_cell on a tlschan "
+ "(%p with ID " U64_FORMAT " but no conn",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ }
- return 1;
+ return written;
}
/**
@@ -652,14 +699,22 @@ static int
channel_tls_write_var_cell_method(channel_t *chan, var_cell_t *var_cell)
{
channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+ int written = 0;
tor_assert(tlschan);
tor_assert(var_cell);
- tor_assert(tlschan->conn);
- connection_or_write_var_cell_to_buf(var_cell, tlschan->conn);
+ if (tlschan->conn) {
+ connection_or_write_var_cell_to_buf(var_cell, tlschan->conn);
+ ++written;
+ } else {
+ log_info(LD_CHANNEL,
+ "something called write_var_cell on a tlschan "
+ "(%p with ID " U64_FORMAT " but no conn",
+ chan, U64_PRINTF_ARG(chan->global_identifier));
+ }
- return 1;
+ return written;
}
/*************************************************
diff --git a/src/or/connection.c b/src/or/connection.c
index 942bfc598..0a01e5020 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -540,6 +540,22 @@ connection_free_(connection_t *conn)
or_handshake_state_free(or_conn->handshake_state);
or_conn->handshake_state = NULL;
tor_free(or_conn->nickname);
+ if (or_conn->chan) {
+ /* Owww, this shouldn't happen, but... */
+ log_info(LD_CHANNEL,
+ "Freeing orconn at %p, saw channel %p with ID "
+ U64_FORMAT " left un-NULLed",
+ or_conn, TLS_CHAN_TO_BASE(or_conn->chan),
+ U64_PRINTF_ARG(
+ TLS_CHAN_TO_BASE(or_conn->chan)->global_identifier));
+ if (!(TLS_CHAN_TO_BASE(or_conn->chan)->state == CHANNEL_STATE_CLOSED ||
+ TLS_CHAN_TO_BASE(or_conn->chan)->state == CHANNEL_STATE_ERROR)) {
+ channel_close_for_error(TLS_CHAN_TO_BASE(or_conn->chan));
+ }
+
+ or_conn->chan->conn = NULL;
+ or_conn->chan = NULL;
+ }
}
if (conn->type == CONN_TYPE_AP) {
entry_connection_t *entry_conn = TO_ENTRY_CONN(conn);
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 089de93f7..dbf05a6fc 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -691,6 +691,11 @@ connection_or_about_to_close(or_connection_t *or_conn)
/* Tell the controlling channel we're closed */
if (or_conn->chan) {
channel_closed(TLS_CHAN_TO_BASE(or_conn->chan));
+ /*
+ * NULL this out because the channel might hang around a little
+ * longer before channel_run_cleanup() gets it.
+ */
+ or_conn->chan->conn = NULL;
or_conn->chan = NULL;
}