[tor-bugs] #30344 [Core Tor/Tor]: conn_read_callback is called on connections that are marked for closed
Tor Bug Tracker & Wiki
blackhole at torproject.org
Tue Apr 30 16:03:27 UTC 2019
#30344: conn_read_callback is called on connections that are marked for closed
------------------------------+--------------------------
Reporter: robgjansen | Owner: (none)
Type: defect | Status: new
Priority: Medium | Milestone:
Component: Core Tor/Tor | Version: Tor: 0.3.5.8
Severity: Normal | Keywords:
Actual Points: | Parent ID:
Points: | Reviewer:
Sponsor: |
------------------------------+--------------------------
There is a bug causing busy loops in Libevent and infinite loops in the
Shadow simulator. In my Shadow simulations, I have observed that
`conn_read_callback` is getting called on a connection that is marked for
close.
This is similar to #5263, and as described there, I believe it is a bug
for `conn_read_callback` to be called on sockets that are marked for
close.
The bug is problematic in Shadow when the marked connection also wants to
flush, but attempting to write the outbuf inside `conn_close_if_marked`
fails because the write would block (because the kernel write buffer is
already full). Because it still wants to flush, the connection does not
get closed, but the connection remains readable causing Libevent to
continue looping on `conn_read_callback` until the socket buffer can
actually write. This wastes CPU resources in Tor, and causes an infinite
loop in Shadow because Shadow's discrete-event time does not advance
during this loop.
I found the bug on 0.3.5.8, and it is probably present at least since
then.
I think the conn should not be waiting for read events when it is marked.
I'm not sure where in the code this assumption is first violated, but the
following patch fixed the issue in my Shadow simulations:
{{{
diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c
index 6e2b300..e82c77a 100644
--- a/src/core/mainloop/mainloop.c
+++ b/src/core/mainloop/mainloop.c
@@ -894,6 +894,21 @@ conn_read_callback(evutil_socket_t fd, short event,
void *_conn)
}
assert_connection_ok(conn, time(NULL));
+ if (conn->marked_for_close && connection_is_reading(conn)) {
+ /* Libevent says we can read, but we are marked so we will never
try
+ * to read again. We will try to close the connection below inside
of
+ * close_closeable_connections(), but let's make sure not to cause
+ * Libevent to spin on conn_read_callback() while we wait for the
+ * socket to let us flush to it.*/
+ connection_stop_reading(conn);
+
+ /* Now, if we still have data to flush, then make sure Libevent
tells
+ * us when the conn will allow us to write the bytes. */
+ if (connection_wants_to_flush(conn) &&
!connection_is_writing(conn)) {
+ connection_start_writing(conn);
+ }
+ }
+
if (smartlist_len(closeable_connection_lst))
close_closeable_connections();
}
}}}
--
Ticket URL: <https://trac.torproject.org/projects/tor/ticket/30344>
Tor Bug Tracker & Wiki <https://trac.torproject.org/>
The Tor Project: anonymity online
More information about the tor-bugs
mailing list